cherry-styled-components 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +89 -28
  2. package/dist/avatar-dropzone.js +8 -8
  3. package/dist/avatar.d.ts +17 -0
  4. package/dist/avatar.js +68 -0
  5. package/dist/button.js +15 -12
  6. package/dist/callout.d.ts +13 -0
  7. package/dist/callout.js +121 -0
  8. package/dist/chat-input.d.ts +18 -0
  9. package/dist/chat-input.js +257 -0
  10. package/dist/chat-launcher.d.ts +10 -0
  11. package/dist/chat-launcher.js +78 -0
  12. package/dist/chat-message-list.d.ts +12 -0
  13. package/dist/chat-message-list.js +88 -0
  14. package/dist/chat-message.d.ts +16 -0
  15. package/dist/chat-message.js +56 -0
  16. package/dist/chat-panel.d.ts +25 -0
  17. package/dist/chat-panel.js +163 -0
  18. package/dist/chat-provider.d.ts +86 -0
  19. package/dist/chat-provider.js +295 -0
  20. package/dist/chat-showcase.d.ts +18 -0
  21. package/dist/chat-showcase.js +234 -0
  22. package/dist/chat-sources.d.ts +10 -0
  23. package/dist/chat-sources.js +41 -0
  24. package/dist/chat-typing.d.ts +7 -0
  25. package/dist/chat-typing.js +44 -0
  26. package/dist/dropzone.js +14 -14
  27. package/dist/icon-button.js +7 -7
  28. package/dist/index.d.ts +13 -0
  29. package/dist/index.js +18 -3
  30. package/dist/input.js +6 -6
  31. package/dist/modal.js +6 -6
  32. package/dist/prose.d.ts +17 -0
  33. package/dist/prose.js +75 -0
  34. package/dist/spinner.d.ts +11 -0
  35. package/dist/spinner.js +21 -0
  36. package/dist/styled-components/client-theme-provider.js +13 -3
  37. package/dist/tabs.js +6 -7
  38. package/dist/theme-toggle.js +5 -5
  39. package/dist/toast.d.ts +2 -2
  40. package/dist/utils/index.d.ts +2 -0
  41. package/dist/utils/mixins.d.ts +30 -0
  42. package/dist/utils/mixins.js +24 -3
  43. package/dist/utils/use-lock-body-scroll.d.ts +5 -0
  44. package/dist/utils/use-lock-body-scroll.js +25 -0
  45. package/dist/utils/use-media-query.d.ts +14 -0
  46. package/dist/utils/use-media-query.js +28 -0
  47. package/package.json +15 -14
package/README.md CHANGED
@@ -36,7 +36,55 @@ export default function App() {
36
36
 
37
37
  The built-in `theme` and `themeDark` objects are a starting point; both are plain objects you can extend or replace to white-label the system. Styled props use a `$` prefix (`$variant`, `$size`, `$fullWidth`) so they never leak into the DOM.
38
38
 
39
- The library ships form components (Button, Input, Select, Textarea, Toggle, Range, Password, Checkbox, Radio, Dropzone, AvatarDropzone), layout primitives (Container, Grid, Col, Flex, Box, MaxWidth, Space), and interactive components (Accordion, Modal, Toast, ThemeToggle, Icon, IconButton). See the [component docs](https://cherry.al/) for the full API.
39
+ The library ships form components (Button, Input, Select, Textarea, Toggle, Range, Password, Checkbox, Radio, Dropzone, AvatarDropzone), layout primitives (Container, Grid, Col, Flex, Box, MaxWidth, Space), interactive components (Accordion, Modal, Toast, ThemeToggle, Icon, IconButton), content components (Prose, Callout, Avatar), and a chat kit (see below). See the [component docs](https://cherry.al/) for the full API.
40
+
41
+ ## Chat kit
42
+
43
+ Cherry ships everything needed to build an AI-assistant chat UI, split into a headless provider and presentational components. The provider owns panel state, focus management, the transcript, and streaming bookkeeping; **the app owns the transport** — Cherry never fetches, parses SSE, or assumes an endpoint.
44
+
45
+ ```tsx
46
+ import {
47
+ ChatInput,
48
+ ChatLauncher,
49
+ ChatMessage,
50
+ ChatMessageList,
51
+ ChatPanel,
52
+ ChatProvider,
53
+ Prose,
54
+ useChat,
55
+ } from "cherry-styled-components";
56
+
57
+ <ChatProvider
58
+ onSend={async (question, { signal, history, setAssistant }) => {
59
+ const res = await fetch("/api/chat", {
60
+ method: "POST",
61
+ body: JSON.stringify({ question, history }),
62
+ signal,
63
+ });
64
+ for await (const text of readMyStream(res)) {
65
+ setAssistant(text); // patches the same assistant bubble on each call
66
+ }
67
+ setAssistant(<Prose $compact>{renderMarkdown(text)}</Prose>, {
68
+ text, // plain-text mirror used for the next request's history
69
+ sources: [{ id: "1", label: "Docs", href: "/docs" }],
70
+ });
71
+ }}
72
+ >
73
+ <ChatLauncher $glow />
74
+ <ChatPanel>
75
+ <MyTranscript /> {/* map useChat().messages into ChatMessageList */}
76
+ <ChatInput $glow />
77
+ </ChatPanel>
78
+ </ChatProvider>;
79
+ ```
80
+
81
+ - `ChatProvider` — headless state: `useChat()` returns `{ isOpen, open, close, toggle, messages, input, setInput, loading, error, send, ask, reset, inputRef }`. Props: `onSend`, `greeting`, `historyLimit`, `shortcut` (Cmd/Ctrl+I by default, `null` to disable), and `$showcase`.
82
+ - `$showcase` — demo mode. Chat input matching a showcase command is answered locally with a live rendering of that element; everything else still goes to `onSend` (which becomes optional). `help` lists the commands: `list` (the component catalog), `callout`, `avatar`, `prose`, `sources`, and `typing`. Off by default — without `$showcase` every message goes to the transport.
83
+ - `ChatPanel` — the shell. `$variant="drawer"` (fixed side panel, full-screen modal below `lg`), `"inline"` (flows with the page), or `"fullscreen"`. Handles dialog semantics, focus trapping, `inert` siblings, and body scroll locking while modal.
84
+ - `ChatMessageList` — scroll container with stick-to-bottom behavior that releases when the reader scrolls up.
85
+ - `ChatMessage` — `$role="user"` (filled bubble) or `"assistant"` (full-width, pair with `Prose` for markdown), plus an `$avatar` slot.
86
+ - `ChatInput` — auto-growing composer; Enter submits, Shift+Enter breaks the line. `$glow` opts into the animated rainbow border and sparkles.
87
+ - `ChatLauncher`, `ChatTyping`, `ChatSources`/`ChatSource` — the "Ask AI" pill, the typing indicator, and the source-chip row.
40
88
 
41
89
  ## Theming
42
90
 
@@ -150,33 +198,46 @@ The route is handled in `src/main.tsx` and the previews live in `src/preview.tsx
150
198
 
151
199
  ### Available previews
152
200
 
153
- | Name | Renders |
154
- | ------------------ | ------------------------------------------------- |
155
- | `accordion` | Card accordion, open by default |
156
- | `accordion-inline` | Inline accordion variant, open by default |
157
- | `avatar-dropzone` | Empty avatar dropzone, default size |
158
- | `box` | Box surface with a placeholder block |
159
- | `button` | Primary filled button |
160
- | `button-secondary` | Secondary filled button |
161
- | `button-tertiary` | Tertiary filled button |
162
- | `button-outline` | Primary outline button |
163
- | `checkbox` | Checked checkbox |
164
- | `dropzone` | Block dropzone with prompt, browse, and hint text |
165
- | `dropzone-inline` | Inline dropzone variant |
166
- | `flex` | Flex row with three placeholder blocks |
167
- | `grid` | Three-column grid with a full-width row |
168
- | `icon` | Cherry icon at 48px |
169
- | `icon-button` | Icon button with a settings icon |
170
- | `input` | Text input with label and placeholder |
171
- | `modal` | Modal, already open on a backdrop |
172
- | `password` | Password field with label and placeholder |
173
- | `radio` | Checked radio button |
174
- | `range` | Range slider |
175
- | `select` | Select with label |
176
- | `textarea` | Textarea with label and value |
177
- | `theme-toggle` | Pill-shaped sun/moon theme switch |
178
- | `toast` | Success, error, and info toasts, fired on mount |
179
- | `toggle` | Checked toggle |
201
+ | Name | Renders |
202
+ | ------------------ | ------------------------------------------------------ |
203
+ | `accordion` | Card accordion, open by default |
204
+ | `accordion-inline` | Inline accordion variant, open by default |
205
+ | `avatar` | Avatar with initials and icon fallbacks, three sizes |
206
+ | `avatar-dropzone` | Empty avatar dropzone, default size |
207
+ | `box` | Box surface with a placeholder block |
208
+ | `button` | Primary filled button |
209
+ | `button-secondary` | Secondary filled button |
210
+ | `button-tertiary` | Tertiary filled button |
211
+ | `button-outline` | Primary outline button |
212
+ | `callout` | The five callout intents stacked |
213
+ | `chat` | Chat drawer with launcher and fake streaming transport |
214
+ | `chat-fullscreen` | Fullscreen chat variant behind a launcher |
215
+ | `chat-glow` | Chat drawer with the rainbow glow treatment |
216
+ | `chat-inline` | Inline chat panel embedded in the page |
217
+ | `chat-input` | Standalone chat composer |
218
+ | `chat-input-glow` | Chat composer with the rainbow glow treatment |
219
+ | `chat-launcher` | "Ask AI" launcher pill with glow |
220
+ | `chat-message` | Static user and assistant messages |
221
+ | `chat-typing` | Three-dot typing indicator |
222
+ | `checkbox` | Checked checkbox |
223
+ | `dropzone` | Block dropzone with prompt, browse, and hint text |
224
+ | `dropzone-inline` | Inline dropzone variant |
225
+ | `flex` | Flex row with three placeholder blocks |
226
+ | `grid` | Three-column grid with a full-width row |
227
+ | `icon` | Cherry icon at 48px |
228
+ | `icon-button` | Icon button with a settings icon |
229
+ | `input` | Text input with label and placeholder |
230
+ | `modal` | Modal, already open on a backdrop |
231
+ | `password` | Password field with label and placeholder |
232
+ | `prose` | Markdown-style content with Cherry typography |
233
+ | `spinner` | Rotating loading indicator in three sizes |
234
+ | `radio` | Checked radio button |
235
+ | `range` | Range slider |
236
+ | `select` | Select with label |
237
+ | `textarea` | Textarea with label and value |
238
+ | `theme-toggle` | Pill-shaped sun/moon theme switch |
239
+ | `toast` | Success, error, and info toasts, fired on mount |
240
+ | `toggle` | Checked toggle |
180
241
 
181
242
  Pure layout primitives with no visual output of their own (Container, Col, MaxWidth, Space) have no preview entry.
182
243
 
@@ -1,12 +1,11 @@
1
1
  "use client";
2
2
  "use client";
3
- import { resetButton } from "./utils/mixins.js";
3
+ import { alpha, resetButton } from "./utils/mixins.js";
4
4
  import { Icon } from "./icon.js";
5
5
  import { matchesAccept } from "./dropzone.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
8
8
  import styled, { css } from "styled-components";
9
- import { rgba } from "polished";
10
9
  //#region src/lib/avatar-dropzone.tsx
11
10
  var avatarSizes = {
12
11
  small: {
@@ -115,7 +114,7 @@ function LocalAvatarDropzone({ $size, $icon = "User", $maxBytes, "aria-label": a
115
114
  var AvatarDropzone = /*#__PURE__*/ forwardRef(LocalAvatarDropzone);
116
115
  var StyledAvatarDropzoneWrapper = styled.span.withConfig({
117
116
  displayName: "avatar-dropzone__StyledAvatarDropzoneWrapper",
118
- componentId: "sc-38b0b6de-0"
117
+ componentId: "sc-758cb640-0"
119
118
  })([
120
119
  `position:relative;display:inline-flex;width:`,
121
120
  `px;height:`,
@@ -123,7 +122,7 @@ var StyledAvatarDropzoneWrapper = styled.span.withConfig({
123
122
  ], ({ $size }) => avatarSizes[$size ?? "default"].box, ({ $size }) => avatarSizes[$size ?? "default"].box);
124
123
  var StyledAvatarDropzone = styled.button.withConfig({
125
124
  displayName: "avatar-dropzone__StyledAvatarDropzone",
126
- componentId: "sc-38b0b6de-1"
125
+ componentId: "sc-758cb640-1"
127
126
  })([
128
127
  ``,
129
128
  `;font-family:inherit;display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;overflow:hidden;border:2px `,
@@ -142,16 +141,17 @@ var StyledAvatarDropzone = styled.button.withConfig({
142
141
  ], resetButton, ({ $hasImage }) => $hasImage ? "solid" : "dashed", ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayDark, ({ $size }) => avatarSizes[$size ?? "default"].icon, ({ $size }) => avatarSizes[$size ?? "default"].icon, ({ theme }) => theme.colors.primary, ({ theme, $dragOver }) => $dragOver && css([
143
142
  `border-color:`,
144
143
  `;background:`,
145
- `;`
146
- ], theme.colors.primary, rgba(theme.colors.primary, theme.isDark ? .12 : .05)), ({ theme }) => theme.colors.primary, ({ theme }) => rgba(theme.colors.primary, theme.isDark ? .1 : .04), ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primaryLight);
144
+ `;:root.dark &{background:`,
145
+ `;}`
146
+ ], theme.colors.primary, alpha(theme.colors.primary, theme.isDark ? 12 : 5), alpha(theme.colors.primary, 12)), ({ theme }) => theme.colors.primary, ({ theme }) => alpha(theme.colors.primary, theme.isDark ? 10 : 4), ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primaryLight);
147
147
  var StyledAvatarRemove = styled.button.withConfig({
148
148
  displayName: "avatar-dropzone__StyledAvatarRemove",
149
- componentId: "sc-38b0b6de-2"
149
+ componentId: "sc-758cb640-2"
150
150
  })([
151
151
  ``,
152
152
  `;position:absolute;top:0;right:0;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;color:#ffffff;background:`,
153
153
  `;transition:background 0.3s ease;& svg{width:14px;height:14px;}&:hover:not(:disabled){background:`,
154
154
  `;}&:disabled{cursor:not-allowed;opacity:0.6;}`
155
- ], resetButton, ({ theme }) => rgba(theme.colors.dark, .6), ({ theme }) => theme.colors.error);
155
+ ], resetButton, ({ theme }) => alpha(theme.colors.dark, 60), ({ theme }) => theme.colors.error);
156
156
  //#endregion
157
157
  export { AvatarDropzone };
@@ -0,0 +1,17 @@
1
+ import { default as React } from 'react';
2
+ import { IconProps } from './icon';
3
+ export type AvatarSize = "small" | "default" | "big";
4
+ export type AvatarColor = "primary" | "secondary" | "tertiary" | "gray";
5
+ export interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
6
+ $size?: AvatarSize;
7
+ /** Image URL. Falls back to initials, then to the icon, if absent. */
8
+ $src?: string;
9
+ $alt?: string;
10
+ /** Full name or label; the first letters of its first two words are shown. */
11
+ $name?: string;
12
+ /** Fallback icon used when there is no image and no name. */
13
+ $icon?: IconProps;
14
+ $color?: AvatarColor;
15
+ }
16
+ declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
17
+ export { Avatar };
package/dist/avatar.js ADDED
@@ -0,0 +1,68 @@
1
+ "use client";
2
+ "use client";
3
+ import { darkFilledTextRule, filledTextColor } from "./utils/mixins.js";
4
+ import { Icon } from "./icon.js";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import { forwardRef } from "react";
7
+ import styled, { css } from "styled-components";
8
+ //#region src/lib/avatar.tsx
9
+ var avatarSizes = {
10
+ small: {
11
+ box: 28,
12
+ icon: 14
13
+ },
14
+ default: {
15
+ box: 36,
16
+ icon: 18
17
+ },
18
+ big: {
19
+ box: 48,
20
+ icon: 24
21
+ }
22
+ };
23
+ var avatarColors = {
24
+ primary: (theme) => theme.colors.primary,
25
+ secondary: (theme) => theme.colors.secondary,
26
+ tertiary: (theme) => theme.colors.tertiary,
27
+ gray: (theme) => theme.colors.grayDark
28
+ };
29
+ function toInitials(name) {
30
+ return name.trim().split(/\s+/).slice(0, 2).map((word) => word[0] ?? "").join("").toUpperCase();
31
+ }
32
+ var StyledAvatar = styled.span.withConfig({
33
+ displayName: "avatar__StyledAvatar",
34
+ componentId: "sc-d3a5da79-0"
35
+ })([``, `;`], ({ theme, $size = "default", $color = "primary" }) => {
36
+ const { box } = avatarSizes[$size];
37
+ return css([
38
+ `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;width:`,
39
+ `px;height:`,
40
+ `px;border-radius:50%;background:`,
41
+ `;color:`,
42
+ `;font-size:`,
43
+ `px;line-height:1;font-weight:600;user-select:none;`,
44
+ `;& img{width:100%;height:100%;object-fit:cover;display:block;}`
45
+ ], box, box, avatarColors[$color](theme), filledTextColor(theme), Math.round(box * .38), darkFilledTextRule(theme));
46
+ });
47
+ function LocalAvatar({ $size = "default", $src, $alt, $name, $icon = "User", $color, ...props }, ref) {
48
+ const initials = $name ? toInitials($name) : "";
49
+ const fallbackLabel = $src || initials ? void 0 : $alt ?? $name;
50
+ return /*#__PURE__*/ jsx(StyledAvatar, {
51
+ $size,
52
+ $color,
53
+ role: fallbackLabel ? "img" : void 0,
54
+ "aria-label": fallbackLabel,
55
+ ...props,
56
+ ref,
57
+ children: $src ? /*#__PURE__*/ jsx("img", {
58
+ src: $src,
59
+ alt: $alt ?? $name ?? ""
60
+ }) : initials ? initials : /*#__PURE__*/ jsx(Icon, {
61
+ name: $icon,
62
+ size: avatarSizes[$size].icon
63
+ })
64
+ });
65
+ }
66
+ var Avatar = /*#__PURE__*/ forwardRef(LocalAvatar);
67
+ //#endregion
68
+ export { Avatar };
package/dist/button.js CHANGED
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
  "use client";
3
- import { formElementHeightStyles, resetButton } from "./utils/mixins.js";
3
+ import { darkFilledTextRule, filledTextColor, formElementHeightStyles, resetButton, shade, tint } from "./utils/mixins.js";
4
4
  import { jsxs } from "react/jsx-runtime";
5
5
  import { forwardRef } from "react";
6
6
  import styled, { css } from "styled-components";
7
- import { darken, lighten } from "polished";
8
7
  //#region src/lib/button.tsx
9
8
  var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabled) => css([
10
9
  ``,
@@ -18,9 +17,10 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
18
17
  ` `,
19
18
  ` `,
20
19
  ``
21
- ], resetButton, theme.isDark ? theme.colors.dark : theme.colors.light, !disabled && $variant === "primary" && css([
20
+ ], resetButton, filledTextColor(theme), !disabled && $variant === "primary" && css([
22
21
  `color:`,
23
- `;background:`,
22
+ `;`,
23
+ ` background:`,
24
24
  `;border:solid 2px `,
25
25
  `;box-shadow:0 0 0 0px `,
26
26
  `;&:hover{background:`,
@@ -29,9 +29,10 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
29
29
  `;}&:focus{box-shadow:0 0 0 4px `,
30
30
  `;}&:active{box-shadow:0 0 0 2px `,
31
31
  `;}`
32
- ], $outline ? theme.colors.primary : theme.isDark ? theme.colors.dark : theme.colors.light, $outline ? "transparent" : theme.colors.primary, theme.colors.primary, theme.colors.primary, $outline ? "transparent" : theme.colors.primaryDark, theme.colors.primaryDark, $outline && `color: ${theme.colors.primaryDark}`, theme.colors.primaryLight, theme.colors.primaryLight), !disabled && $variant === "secondary" && css([
32
+ ], $outline ? theme.colors.primary : filledTextColor(theme), !$outline && darkFilledTextRule(theme), $outline ? "transparent" : theme.colors.primary, theme.colors.primary, theme.colors.primary, $outline ? "transparent" : theme.colors.primaryDark, theme.colors.primaryDark, $outline && `color: ${theme.colors.primaryDark}`, theme.colors.primaryLight, theme.colors.primaryLight), !disabled && $variant === "secondary" && css([
33
33
  `color:`,
34
- `;background:`,
34
+ `;`,
35
+ ` background:`,
35
36
  `;border:solid 2px `,
36
37
  `;box-shadow:0 0 0 0px `,
37
38
  `;&:hover{background:`,
@@ -40,9 +41,10 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
40
41
  `;}&:focus{box-shadow:0 0 0 4px `,
41
42
  `;}&:active{box-shadow:0 0 0 2px `,
42
43
  `;}`
43
- ], $outline ? theme.colors.secondary : theme.isDark ? theme.colors.dark : theme.colors.light, $outline ? "transparent" : theme.colors.secondary, theme.colors.secondary, theme.colors.secondary, $outline ? "transparent" : theme.colors.secondaryDark, theme.colors.secondaryDark, $outline && `color: ${theme.colors.secondaryDark}`, theme.colors.secondaryLight, theme.colors.secondaryLight), !disabled && $variant === "tertiary" && css([
44
+ ], $outline ? theme.colors.secondary : filledTextColor(theme), !$outline && darkFilledTextRule(theme), $outline ? "transparent" : theme.colors.secondary, theme.colors.secondary, theme.colors.secondary, $outline ? "transparent" : theme.colors.secondaryDark, theme.colors.secondaryDark, $outline && `color: ${theme.colors.secondaryDark}`, theme.colors.secondaryLight, theme.colors.secondaryLight), !disabled && $variant === "tertiary" && css([
44
45
  `color:`,
45
- `;background:`,
46
+ `;`,
47
+ ` background:`,
46
48
  `;border:solid 2px `,
47
49
  `;box-shadow:0 0 0 0px `,
48
50
  `;&:hover{background:`,
@@ -51,9 +53,10 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
51
53
  `;}&:focus{box-shadow:0 0 0 4px `,
52
54
  `;}&:active{box-shadow:0 0 0 2px `,
53
55
  `;}`
54
- ], $outline ? theme.colors.tertiary : theme.isDark ? theme.colors.dark : theme.colors.light, $outline ? "transparent" : theme.colors.tertiary, theme.colors.tertiary, theme.colors.tertiary, $outline ? "transparent" : theme.colors.tertiaryDark, theme.colors.tertiaryDark, $outline && `color: ${theme.colors.tertiaryDark}`, theme.colors.tertiaryLight, theme.colors.tertiaryLight), !disabled && $error && css([
56
+ ], $outline ? theme.colors.tertiary : filledTextColor(theme), !$outline && darkFilledTextRule(theme), $outline ? "transparent" : theme.colors.tertiary, theme.colors.tertiary, theme.colors.tertiary, $outline ? "transparent" : theme.colors.tertiaryDark, theme.colors.tertiaryDark, $outline && `color: ${theme.colors.tertiaryDark}`, theme.colors.tertiaryLight, theme.colors.tertiaryLight), !disabled && $error && css([
55
57
  `color:`,
56
- `;background:`,
58
+ `;`,
59
+ ` background:`,
57
60
  `;border:solid 2px `,
58
61
  `;box-shadow:0 0 0 0px `,
59
62
  `;&:hover{background:`,
@@ -62,7 +65,7 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
62
65
  `;}&:focus{box-shadow:0 0 0 4px `,
63
66
  `;}&:active{box-shadow:0 0 0 2px `,
64
67
  `;}`
65
- ], $outline ? theme.colors.error : theme.isDark ? theme.colors.dark : theme.colors.light, $outline ? "transparent" : theme.colors.error, theme.colors.error, theme.colors.error, $outline ? "transparent" : darken(.1, theme.colors.error), darken(.1, theme.colors.error), $outline && `color: ${darken(.1, theme.colors.error)}`, lighten(.1, theme.colors.error), lighten(.1, theme.colors.error)), formElementHeightStyles($size), $size === "big" ? `font-size: ${theme.fontSizes.buttonBig.lg};
68
+ ], $outline ? theme.colors.error : filledTextColor(theme), !$outline && darkFilledTextRule(theme), $outline ? "transparent" : theme.colors.error, theme.colors.error, theme.colors.error, $outline ? "transparent" : shade(theme.colors.error, 10), shade(theme.colors.error, 10), $outline && `color: ${shade(theme.colors.error, 10)}`, tint(theme.colors.error, 10), tint(theme.colors.error, 10)), formElementHeightStyles($size), $size === "big" ? `font-size: ${theme.fontSizes.buttonBig.lg};
66
69
  line-height: ${theme.lineHeights.buttonBig.lg};
67
70
  padding: 18px 30px;
68
71
  ` : $size === "small" ? `font-size: ${theme.fontSizes.buttonSmall.lg};
@@ -77,7 +80,7 @@ var buttonStyles = (theme, $variant, $size, $outline, $fullWidth, $error, disabl
77
80
  `, $fullWidth && `width: 100%;`);
78
81
  var StyledButton = styled.button.withConfig({
79
82
  displayName: "button__StyledButton",
80
- componentId: "sc-2f3ba034-0"
83
+ componentId: "sc-286fdf36-0"
81
84
  })([``, ``], ({ theme, $variant, $error, $size, $outline, $fullWidth, disabled }) => buttonStyles(theme, $variant, $size, $outline, $fullWidth, $error, disabled));
82
85
  function LocalButton({ $variant = "primary", ...props }, ref) {
83
86
  return /*#__PURE__*/ jsxs(StyledButton, {
@@ -0,0 +1,13 @@
1
+ import { default as React } from 'react';
2
+ import { IconProps } from './icon';
3
+ export type CalloutType = "note" | "info" | "warning" | "danger" | "success";
4
+ export interface CalloutProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ $type?: CalloutType;
7
+ /** Overrides the icon the type would pick, or supplies one when untyped. */
8
+ $icon?: IconProps;
9
+ /** Renders without an icon. */
10
+ $hideIcon?: boolean;
11
+ }
12
+ declare const Callout: React.ForwardRefExoticComponent<CalloutProps & React.RefAttributes<HTMLDivElement>>;
13
+ export { Callout };
@@ -0,0 +1,121 @@
1
+ "use client";
2
+ "use client";
3
+ import { styledSmall } from "./utils/typography.js";
4
+ import { Icon } from "./icon.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { forwardRef } from "react";
7
+ import styled, { css } from "styled-components";
8
+ //#region src/lib/callout.tsx
9
+ var calloutTints = {
10
+ note: {
11
+ light: {
12
+ border: "#0ea5e933",
13
+ background: "#f0f9ff80",
14
+ text: "#0c4a6e"
15
+ },
16
+ dark: {
17
+ border: "#0ea5e94d",
18
+ background: "#0ea5e91a",
19
+ text: "#bae6fd"
20
+ }
21
+ },
22
+ info: {
23
+ light: {
24
+ border: "#71717a33",
25
+ background: "#fafafa80",
26
+ text: "#18181b"
27
+ },
28
+ dark: {
29
+ border: "#71717a4d",
30
+ background: "#71717a1a",
31
+ text: "#e4e4e7"
32
+ }
33
+ },
34
+ warning: {
35
+ light: {
36
+ border: "#f59e0b33",
37
+ background: "#fffbeb80",
38
+ text: "#78350f"
39
+ },
40
+ dark: {
41
+ border: "#f59e0b4d",
42
+ background: "#f59e0b1a",
43
+ text: "#fde68a"
44
+ }
45
+ },
46
+ danger: {
47
+ light: {
48
+ border: "#ef444433",
49
+ background: "#fef2f280",
50
+ text: "#7f1d1d"
51
+ },
52
+ dark: {
53
+ border: "#ef44444d",
54
+ background: "#ef44441a",
55
+ text: "#fecaca"
56
+ }
57
+ },
58
+ success: {
59
+ light: {
60
+ border: "#10b98133",
61
+ background: "#ecfdf580",
62
+ text: "#064e3b"
63
+ },
64
+ dark: {
65
+ border: "#10b9814d",
66
+ background: "#10b9811a",
67
+ text: "#a7f3d0"
68
+ }
69
+ }
70
+ };
71
+ var calloutIcons = {
72
+ note: "CircleAlert",
73
+ info: "Info",
74
+ warning: "TriangleAlert",
75
+ danger: "OctagonAlert",
76
+ success: "Check"
77
+ };
78
+ var tintStyles = (tint) => css([
79
+ `border-color:`,
80
+ `;background:`,
81
+ `;& .callout-icon svg,& .callout-content,& .callout-content p{color:`,
82
+ `;}`
83
+ ], tint.border, tint.background, tint.text);
84
+ var StyledCallout = styled.div.withConfig({
85
+ displayName: "callout__StyledCallout",
86
+ componentId: "sc-84e10f5e-0"
87
+ })([
88
+ `background:`,
89
+ `;border:solid 1px `,
90
+ `;border-radius:`,
91
+ `;padding:20px;margin:0;max-width:100%;color:`,
92
+ `;display:flex;`,
93
+ `;& .callout-icon{display:flex;flex-shrink:0;margin:3px 10px 0 0;& svg{width:16px;height:16px;}}& .callout-content{display:flex;flex-direction:column;gap:10px;min-width:0;& > *:first-child{margin-top:0;}& > *:last-child{margin-bottom:0;}}`,
94
+ ``
95
+ ], ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayDark, ({ theme }) => styledSmall(theme), ({ $type, theme }) => $type && css([
96
+ ``,
97
+ `;`,
98
+ `;:root.dark &{`,
99
+ `;}`
100
+ ], tintStyles(calloutTints[$type].light), theme.isDark && tintStyles(calloutTints[$type].dark), tintStyles(calloutTints[$type].dark)));
101
+ function LocalCallout({ children, $type, $icon, $hideIcon, ...props }, ref) {
102
+ const iconName = $icon ?? ($type ? calloutIcons[$type] : void 0);
103
+ return /*#__PURE__*/ jsxs(StyledCallout, {
104
+ $type,
105
+ ...props,
106
+ ref,
107
+ children: [!$hideIcon && iconName && /*#__PURE__*/ jsx("span", {
108
+ className: "callout-icon",
109
+ children: /*#__PURE__*/ jsx(Icon, {
110
+ name: iconName,
111
+ size: 16
112
+ })
113
+ }), /*#__PURE__*/ jsx("span", {
114
+ className: "callout-content",
115
+ children
116
+ })]
117
+ });
118
+ }
119
+ var Callout = /*#__PURE__*/ forwardRef(LocalCallout);
120
+ //#endregion
121
+ export { Callout };
@@ -0,0 +1,18 @@
1
+ import { default as React } from 'react';
2
+ export interface ChatInputProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "onChange" | "onSubmit"> {
3
+ /** Controlled value. Defaults to the provider's input state. */
4
+ value?: string;
5
+ onValueChange?: (value: string) => void;
6
+ /** Submit handler. Defaults to the provider's send(). */
7
+ onSend?: (value: string) => void;
8
+ /** Overrides the provider's loading state. */
9
+ $loading?: boolean;
10
+ /** The animated rainbow border + sparkle treatment. Off by default. */
11
+ $glow?: boolean;
12
+ /** Overrides the glow palette. */
13
+ $glowColors?: string[];
14
+ /** Max height in px the textarea may grow to before it scrolls. */
15
+ $maxRows?: number;
16
+ }
17
+ declare const ChatInput: React.ForwardRefExoticComponent<ChatInputProps & React.RefAttributes<HTMLTextAreaElement>>;
18
+ export { ChatInput };