cherry-styled-components 0.2.15 → 0.2.17
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 +7 -6
- package/dist/accordion.js +7 -6
- package/dist/avatar-dropzone.d.ts +3 -3
- package/dist/avatar-dropzone.js +8 -7
- package/dist/avatar.d.ts +3 -3
- package/dist/avatar.js +5 -7
- package/dist/callout.d.ts +3 -3
- package/dist/callout.js +11 -13
- package/dist/chat-input.js +9 -8
- package/dist/chat-launcher.js +3 -2
- package/dist/chat-panel.d.ts +3 -2
- package/dist/chat-panel.js +6 -5
- package/dist/dropzone.d.ts +3 -3
- package/dist/dropzone.js +15 -14
- package/dist/icon-dynamic.d.ts +24 -0
- package/dist/icon-dynamic.js +34 -0
- package/dist/icon.d.ts +39 -5
- package/dist/icon.js +25 -13
- package/dist/index.js +2 -3
- package/dist/input.js +10 -9
- package/dist/modal.js +6 -5
- package/dist/password.js +4 -3
- package/dist/select.js +4 -3
- package/dist/spinner.d.ts +4 -4
- package/dist/spinner.js +4 -3
- package/dist/styled-components/index.d.ts +0 -1
- package/dist/theme-toggle.js +3 -2
- package/dist/toast.d.ts +2 -2
- package/dist/toast.js +9 -8
- package/dist/utils/use-on-click-outside.js +43 -0
- package/package.json +22 -15
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Cherry Design System is a versatile foundation for projects. It offers a white l
|
|
|
10
10
|
Install the package along with its peer dependencies:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install cherry-styled-components react react-dom styled-components
|
|
13
|
+
npm install cherry-styled-components react react-dom styled-components lucide-react
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
@@ -38,6 +38,8 @@ The built-in `theme` and `themeDark` objects are a starting point; both are plai
|
|
|
38
38
|
|
|
39
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
40
|
|
|
41
|
+
Icons come from [lucide](https://lucide.dev/icons/), a peer dependency. Pass an imported component, `<Icon icon={ArrowRight} />`, which ships only that glyph and renders on the server. Component icon props such as Avatar's `$icon` take the same component, or a rendered element. For an icon chosen at runtime, import `DynamicIcon` from `cherry-styled-components/dynamic`: it resolves a name on demand, and only apps that import that subpath carry lucide's dynamic import map.
|
|
42
|
+
|
|
41
43
|
## Chat kit
|
|
42
44
|
|
|
43
45
|
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.
|
|
@@ -100,11 +102,10 @@ A Next.js App Router setup looks like this:
|
|
|
100
102
|
```tsx
|
|
101
103
|
// app/layout.tsx (server component)
|
|
102
104
|
import { cookies } from "next/headers";
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
} from "cherry-styled-components";
|
|
105
|
+
// StyledComponentsRegistry is the one export that depends on Next, so it ships
|
|
106
|
+
// from the `/next` subpath instead of the package root.
|
|
107
|
+
import { StyledComponentsRegistry } from "cherry-styled-components/next";
|
|
108
|
+
import { ClientThemeProvider, themeInitScript } from "cherry-styled-components";
|
|
108
109
|
import { theme, themeDark } from "./theme";
|
|
109
110
|
|
|
110
111
|
export default async function RootLayout({ children }) {
|
package/dist/accordion.js
CHANGED
|
@@ -5,10 +5,11 @@ import { Icon } from "./icon.js";
|
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { useState } from "react";
|
|
7
7
|
import styled, { css } from "styled-components";
|
|
8
|
+
import { ChevronDown } from "lucide-react";
|
|
8
9
|
//#region src/lib/accordion.tsx
|
|
9
10
|
var StyledAccordion = styled.div.withConfig({
|
|
10
11
|
displayName: "accordion__StyledAccordion",
|
|
11
|
-
componentId: "sc-
|
|
12
|
+
componentId: "sc-bafb2fc7-0"
|
|
12
13
|
})([
|
|
13
14
|
`text-align:left;border-radius:`,
|
|
14
15
|
`;margin:0;`,
|
|
@@ -18,7 +19,7 @@ var StyledAccordion = styled.div.withConfig({
|
|
|
18
19
|
], ({ theme, $inline }) => $inline ? "0" : theme.spacing.radius.lg, ({ theme }) => styledText(theme), ({ theme }) => theme.colors.light, ({ theme, $inline }) => !$inline && css([`border:solid 1px `, `;`], theme.colors.grayLight));
|
|
19
20
|
var StyledAccordionTitle = styled.button.withConfig({
|
|
20
21
|
displayName: "accordion__StyledAccordionTitle",
|
|
21
|
-
componentId: "sc-
|
|
22
|
+
componentId: "sc-bafb2fc7-1"
|
|
22
23
|
})([
|
|
23
24
|
`appearance:none;border:none;background:none;font-family:inherit;text-align:left;width:100%;box-sizing:border-box;font-weight:700;cursor:pointer;margin:0;`,
|
|
24
25
|
`;color:`,
|
|
@@ -32,7 +33,7 @@ var StyledAccordionTitle = styled.button.withConfig({
|
|
|
32
33
|
], ({ theme }) => styledText(theme), ({ theme }) => theme.colors.primary, ({ $inline }) => $inline ? "8px 40px 8px 0" : "20px 50px 20px 20px", ({ theme }) => theme.colors.primaryDark, ({ theme }) => theme.spacing.radius.xs, ({ theme }) => theme.colors.primary, ({ $inline }) => $inline ? "0" : "20px", ({ $isOpen }) => $isOpen && css([`transform:translateY(-50%) rotate(180deg);`]));
|
|
33
34
|
var StyledAccordionContent = styled.div.withConfig({
|
|
34
35
|
displayName: "accordion__StyledAccordionContent",
|
|
35
|
-
componentId: "sc-
|
|
36
|
+
componentId: "sc-bafb2fc7-2"
|
|
36
37
|
})([
|
|
37
38
|
`display:grid;grid-template-rows:`,
|
|
38
39
|
`;visibility:`,
|
|
@@ -40,11 +41,11 @@ var StyledAccordionContent = styled.div.withConfig({
|
|
|
40
41
|
], ({ $isOpen }) => $isOpen ? "1fr" : "0fr", ({ $isOpen }) => $isOpen ? "visible" : "hidden");
|
|
41
42
|
var StyledAccordionInner = styled.div.withConfig({
|
|
42
43
|
displayName: "accordion__StyledAccordionInner",
|
|
43
|
-
componentId: "sc-
|
|
44
|
+
componentId: "sc-bafb2fc7-3"
|
|
44
45
|
})([`min-height:0;overflow:clip;`]);
|
|
45
46
|
var StyledAccordionBody = styled.div.withConfig({
|
|
46
47
|
displayName: "accordion__StyledAccordionBody",
|
|
47
|
-
componentId: "sc-
|
|
48
|
+
componentId: "sc-bafb2fc7-4"
|
|
48
49
|
})([
|
|
49
50
|
``,
|
|
50
51
|
`;color:`,
|
|
@@ -74,7 +75,7 @@ function Accordion({ children, title, onToggle, $inline, defaultOpen, open, ...r
|
|
|
74
75
|
children: [
|
|
75
76
|
title,
|
|
76
77
|
" ",
|
|
77
|
-
/*#__PURE__*/ jsx(Icon, {
|
|
78
|
+
/*#__PURE__*/ jsx(Icon, { icon: ChevronDown })
|
|
78
79
|
]
|
|
79
80
|
}), /*#__PURE__*/ jsx(StyledAccordionContent, {
|
|
80
81
|
$isOpen: isOpen,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { DropzoneRejection } from './dropzone';
|
|
3
|
-
import {
|
|
3
|
+
import { IconSource } from './icon';
|
|
4
4
|
export interface AvatarDropzoneProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "onChange" | "children" | "multiple"> {
|
|
5
5
|
/** Visual scale, following the IconButton size scale. */
|
|
6
6
|
$size?: "default" | "big" | "small";
|
|
7
|
-
/**
|
|
8
|
-
$icon?:
|
|
7
|
+
/** Icon shown while no picture is selected: an imported lucide component, or a rendered element. */
|
|
8
|
+
$icon?: IconSource;
|
|
9
9
|
/** Maximum file size in bytes. */
|
|
10
10
|
$maxBytes?: number;
|
|
11
11
|
/** Accessible label for the drop target. */
|
package/dist/avatar-dropzone.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
3
|
import { alpha, resetButton } from "./utils/mixins.js";
|
|
4
|
-
import { Icon } from "./icon.js";
|
|
4
|
+
import { Icon, renderIcon } 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 { User, X } from "lucide-react";
|
|
9
10
|
//#region src/lib/avatar-dropzone.tsx
|
|
10
11
|
var avatarSizes = {
|
|
11
12
|
small: {
|
|
@@ -21,7 +22,7 @@ var avatarSizes = {
|
|
|
21
22
|
icon: 28
|
|
22
23
|
}
|
|
23
24
|
};
|
|
24
|
-
function LocalAvatarDropzone({ $size, $icon =
|
|
25
|
+
function LocalAvatarDropzone({ $size, $icon = User, $maxBytes, "aria-label": ariaLabel = "Upload profile picture", onFileChange, onFileRejected, accept = "image/*", disabled, ...rest }, ref) {
|
|
25
26
|
const [previewUrl, setPreviewUrl] = useState(null);
|
|
26
27
|
const [dragOver, setDragOver] = useState(false);
|
|
27
28
|
const inputRef = useRef(null);
|
|
@@ -87,14 +88,14 @@ function LocalAvatarDropzone({ $size, $icon = "User", $maxBytes, "aria-label": a
|
|
|
87
88
|
children: previewUrl ? /*#__PURE__*/ jsx("img", {
|
|
88
89
|
src: previewUrl,
|
|
89
90
|
alt: ""
|
|
90
|
-
}) :
|
|
91
|
+
}) : renderIcon($icon)
|
|
91
92
|
}),
|
|
92
93
|
previewUrl && /*#__PURE__*/ jsx(StyledAvatarRemove, {
|
|
93
94
|
type: "button",
|
|
94
95
|
"aria-label": "Remove profile picture",
|
|
95
96
|
onClick: removeFile,
|
|
96
97
|
disabled,
|
|
97
|
-
children: /*#__PURE__*/ jsx(Icon, {
|
|
98
|
+
children: /*#__PURE__*/ jsx(Icon, { icon: X })
|
|
98
99
|
}),
|
|
99
100
|
/*#__PURE__*/ jsx("input", {
|
|
100
101
|
ref: inputRef,
|
|
@@ -114,7 +115,7 @@ function LocalAvatarDropzone({ $size, $icon = "User", $maxBytes, "aria-label": a
|
|
|
114
115
|
var AvatarDropzone = /*#__PURE__*/ forwardRef(LocalAvatarDropzone);
|
|
115
116
|
var StyledAvatarDropzoneWrapper = styled.span.withConfig({
|
|
116
117
|
displayName: "avatar-dropzone__StyledAvatarDropzoneWrapper",
|
|
117
|
-
componentId: "sc-
|
|
118
|
+
componentId: "sc-b516c8e0-0"
|
|
118
119
|
})([
|
|
119
120
|
`position:relative;display:inline-flex;width:`,
|
|
120
121
|
`px;height:`,
|
|
@@ -122,7 +123,7 @@ var StyledAvatarDropzoneWrapper = styled.span.withConfig({
|
|
|
122
123
|
], ({ $size }) => avatarSizes[$size ?? "default"].box, ({ $size }) => avatarSizes[$size ?? "default"].box);
|
|
123
124
|
var StyledAvatarDropzone = styled.button.withConfig({
|
|
124
125
|
displayName: "avatar-dropzone__StyledAvatarDropzone",
|
|
125
|
-
componentId: "sc-
|
|
126
|
+
componentId: "sc-b516c8e0-1"
|
|
126
127
|
})([
|
|
127
128
|
``,
|
|
128
129
|
`;font-family:inherit;display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;overflow:hidden;border:2px `,
|
|
@@ -146,7 +147,7 @@ var StyledAvatarDropzone = styled.button.withConfig({
|
|
|
146
147
|
], 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
148
|
var StyledAvatarRemove = styled.button.withConfig({
|
|
148
149
|
displayName: "avatar-dropzone__StyledAvatarRemove",
|
|
149
|
-
componentId: "sc-
|
|
150
|
+
componentId: "sc-b516c8e0-2"
|
|
150
151
|
})([
|
|
151
152
|
``,
|
|
152
153
|
`;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:`,
|
package/dist/avatar.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconSource } from './icon';
|
|
3
3
|
export type AvatarSize = "small" | "default" | "big";
|
|
4
4
|
export type AvatarColor = "primary" | "secondary" | "tertiary" | "gray";
|
|
5
5
|
export interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
@@ -9,8 +9,8 @@ export interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
9
9
|
$alt?: string;
|
|
10
10
|
/** Full name or label; the first letters of its first two words are shown. */
|
|
11
11
|
$name?: string;
|
|
12
|
-
/** Fallback icon used when there is no image and no name. */
|
|
13
|
-
$icon?:
|
|
12
|
+
/** Fallback icon used when there is no image and no name: an imported lucide component, or a rendered element. */
|
|
13
|
+
$icon?: IconSource;
|
|
14
14
|
$color?: AvatarColor;
|
|
15
15
|
}
|
|
16
16
|
declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
|
package/dist/avatar.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
3
|
import { darkFilledTextRule, filledTextColor } from "./utils/mixins.js";
|
|
4
|
-
import {
|
|
4
|
+
import { renderIcon } from "./icon.js";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import { forwardRef } from "react";
|
|
7
7
|
import styled, { css } from "styled-components";
|
|
8
|
+
import { User } from "lucide-react";
|
|
8
9
|
//#region src/lib/avatar.tsx
|
|
9
10
|
var avatarSizes = {
|
|
10
11
|
small: {
|
|
@@ -31,7 +32,7 @@ function toInitials(name) {
|
|
|
31
32
|
}
|
|
32
33
|
var StyledAvatar = styled.span.withConfig({
|
|
33
34
|
displayName: "avatar__StyledAvatar",
|
|
34
|
-
componentId: "sc-
|
|
35
|
+
componentId: "sc-3c0e28ca-0"
|
|
35
36
|
})([``, `;`], ({ theme, $size = "default", $color = "primary" }) => {
|
|
36
37
|
const { box } = avatarSizes[$size];
|
|
37
38
|
return css([
|
|
@@ -44,7 +45,7 @@ var StyledAvatar = styled.span.withConfig({
|
|
|
44
45
|
`;& img{width:100%;height:100%;object-fit:cover;display:block;}`
|
|
45
46
|
], box, box, avatarColors[$color](theme), filledTextColor(theme), Math.round(box * .38), darkFilledTextRule(theme));
|
|
46
47
|
});
|
|
47
|
-
function LocalAvatar({ $size = "default", $src, $alt, $name, $icon =
|
|
48
|
+
function LocalAvatar({ $size = "default", $src, $alt, $name, $icon = User, $color, ...props }, ref) {
|
|
48
49
|
const initials = $name ? toInitials($name) : "";
|
|
49
50
|
const fallbackLabel = $src || initials ? void 0 : $alt ?? $name;
|
|
50
51
|
return /*#__PURE__*/ jsx(StyledAvatar, {
|
|
@@ -57,10 +58,7 @@ function LocalAvatar({ $size = "default", $src, $alt, $name, $icon = "User", $co
|
|
|
57
58
|
children: $src ? /*#__PURE__*/ jsx("img", {
|
|
58
59
|
src: $src,
|
|
59
60
|
alt: $alt ?? $name ?? ""
|
|
60
|
-
}) : initials ? initials :
|
|
61
|
-
name: $icon,
|
|
62
|
-
size: avatarSizes[$size].icon
|
|
63
|
-
})
|
|
61
|
+
}) : initials ? initials : renderIcon($icon, { size: avatarSizes[$size].icon })
|
|
64
62
|
});
|
|
65
63
|
}
|
|
66
64
|
var Avatar = /*#__PURE__*/ forwardRef(LocalAvatar);
|
package/dist/callout.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconSource } from './icon';
|
|
3
3
|
export type CalloutType = "note" | "info" | "warning" | "danger" | "success";
|
|
4
4
|
export interface CalloutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
5
|
children: React.ReactNode;
|
|
6
6
|
$type?: CalloutType;
|
|
7
|
-
/** Overrides the icon the type would pick, or supplies one when untyped. */
|
|
8
|
-
$icon?:
|
|
7
|
+
/** Overrides the icon the type would pick, or supplies one when untyped: an imported lucide component, or a rendered element. */
|
|
8
|
+
$icon?: IconSource;
|
|
9
9
|
/** Renders without an icon. */
|
|
10
10
|
$hideIcon?: boolean;
|
|
11
11
|
}
|
package/dist/callout.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
3
|
import { styledSmall } from "./utils/typography.js";
|
|
4
|
-
import {
|
|
4
|
+
import { renderIcon } from "./icon.js";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { forwardRef } from "react";
|
|
7
7
|
import styled, { css } from "styled-components";
|
|
8
|
+
import { Check, CircleAlert, Info, OctagonAlert, TriangleAlert } from "lucide-react";
|
|
8
9
|
//#region src/lib/callout.tsx
|
|
9
10
|
var calloutTints = {
|
|
10
11
|
note: {
|
|
@@ -69,11 +70,11 @@ var calloutTints = {
|
|
|
69
70
|
}
|
|
70
71
|
};
|
|
71
72
|
var calloutIcons = {
|
|
72
|
-
note:
|
|
73
|
-
info:
|
|
74
|
-
warning:
|
|
75
|
-
danger:
|
|
76
|
-
success:
|
|
73
|
+
note: CircleAlert,
|
|
74
|
+
info: Info,
|
|
75
|
+
warning: TriangleAlert,
|
|
76
|
+
danger: OctagonAlert,
|
|
77
|
+
success: Check
|
|
77
78
|
};
|
|
78
79
|
var tintStyles = (tint) => css([
|
|
79
80
|
`border-color:`,
|
|
@@ -83,7 +84,7 @@ var tintStyles = (tint) => css([
|
|
|
83
84
|
], tint.border, tint.background, tint.text);
|
|
84
85
|
var StyledCallout = styled.div.withConfig({
|
|
85
86
|
displayName: "callout__StyledCallout",
|
|
86
|
-
componentId: "sc-
|
|
87
|
+
componentId: "sc-46cf6e91-0"
|
|
87
88
|
})([
|
|
88
89
|
`background:`,
|
|
89
90
|
`;border:solid 1px `,
|
|
@@ -99,17 +100,14 @@ var StyledCallout = styled.div.withConfig({
|
|
|
99
100
|
`;}`
|
|
100
101
|
], tintStyles(calloutTints[$type].light), theme.isDark && tintStyles(calloutTints[$type].dark), tintStyles(calloutTints[$type].dark)));
|
|
101
102
|
function LocalCallout({ children, $type, $icon, $hideIcon, ...props }, ref) {
|
|
102
|
-
const
|
|
103
|
+
const icon = $icon ?? ($type ? calloutIcons[$type] : void 0);
|
|
103
104
|
return /*#__PURE__*/ jsxs(StyledCallout, {
|
|
104
105
|
$type,
|
|
105
106
|
...props,
|
|
106
107
|
ref,
|
|
107
|
-
children: [!$hideIcon &&
|
|
108
|
+
children: [!$hideIcon && icon && /*#__PURE__*/ jsx("span", {
|
|
108
109
|
className: "callout-icon",
|
|
109
|
-
children:
|
|
110
|
-
name: iconName,
|
|
111
|
-
size: 16
|
|
112
|
-
})
|
|
110
|
+
children: renderIcon(icon, { size: 16 })
|
|
113
111
|
}), /*#__PURE__*/ jsx("span", {
|
|
114
112
|
className: "callout-content",
|
|
115
113
|
children
|
package/dist/chat-input.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Spinner } from "./spinner.js";
|
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { forwardRef, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
10
10
|
import styled, { createGlobalStyle, css, keyframes } from "styled-components";
|
|
11
|
+
import { ArrowUp } from "lucide-react";
|
|
11
12
|
//#region src/lib/chat-input.tsx
|
|
12
13
|
var GLOW_COLORS = [
|
|
13
14
|
"#cc5555",
|
|
@@ -75,7 +76,7 @@ var sparkleFloat = keyframes([`0%,100%{opacity:0;transform:translateY(0) scale(0
|
|
|
75
76
|
var conicStops = (colors) => [...colors, colors[0]].join(", ");
|
|
76
77
|
var StyledChatForm = styled.form.withConfig({
|
|
77
78
|
displayName: "chat-input__StyledChatForm",
|
|
78
|
-
componentId: "sc-
|
|
79
|
+
componentId: "sc-88c29886-0"
|
|
79
80
|
})([
|
|
80
81
|
`display:flex;gap:10px;justify-content:center;align-items:flex-end;background:`,
|
|
81
82
|
`;padding:20px;width:100%;flex-shrink:0;border-top:solid 1px `,
|
|
@@ -83,7 +84,7 @@ var StyledChatForm = styled.form.withConfig({
|
|
|
83
84
|
], ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight);
|
|
84
85
|
var StyledInputWrapper = styled.div.withConfig({
|
|
85
86
|
displayName: "chat-input__StyledInputWrapper",
|
|
86
|
-
componentId: "sc-
|
|
87
|
+
componentId: "sc-88c29886-1"
|
|
87
88
|
})([`position:relative;flex:1;min-width:0;`, ``], ({ $glow, $glowColors = GLOW_COLORS, theme }) => $glow && css([
|
|
88
89
|
`isolation:isolate;&::before{content:"";position:absolute;inset:0;border-radius:`,
|
|
89
90
|
`;background:conic-gradient( from var(--cherry-gradient-angle),`,
|
|
@@ -97,7 +98,7 @@ var StyledInputWrapper = styled.div.withConfig({
|
|
|
97
98
|
], theme.spacing.radius.xs, conicStops($glowColors), rotateGradient, theme.spacing.radius.xs, conicStops($glowColors.map((color) => alpha(color, 40))), rotateGradient, theme.spacing.radius.xs, theme.spacing.radius.xs));
|
|
98
99
|
var StyledRadiantGlow = styled.div.withConfig({
|
|
99
100
|
displayName: "chat-input__StyledRadiantGlow",
|
|
100
|
-
componentId: "sc-
|
|
101
|
+
componentId: "sc-88c29886-2"
|
|
101
102
|
})([
|
|
102
103
|
`position:absolute;inset:-10px;border-radius:20px;pointer-events:none;z-index:-2;opacity:0.6;transition:all 0.3s ease;&::before{content:"";position:absolute;inset:0;border-radius:inherit;background:conic-gradient( from var(--cherry-gradient-angle),`,
|
|
103
104
|
` );animation:`,
|
|
@@ -107,11 +108,11 @@ var StyledRadiantGlow = styled.div.withConfig({
|
|
|
107
108
|
], ({ $glowColors = GLOW_COLORS }) => conicStops($glowColors.map((color) => alpha(color, 40))), rotateGradient, pulseGlow, ({ $isActive }) => $isActive && css([`opacity:1;`]));
|
|
108
109
|
var StyledSparkleContainer = styled.div.withConfig({
|
|
109
110
|
displayName: "chat-input__StyledSparkleContainer",
|
|
110
|
-
componentId: "sc-
|
|
111
|
+
componentId: "sc-88c29886-3"
|
|
111
112
|
})([`position:absolute;inset:-30px;pointer-events:none;overflow:hidden;border-radius:30px;z-index:-3;opacity:0;transition:all 0.3s ease;`, ` @media (prefers-reduced-motion:reduce){display:none;}`], ({ $isActive }) => $isActive && css([`opacity:1;`]));
|
|
112
113
|
var StyledSparkle = styled.div.withConfig({
|
|
113
114
|
displayName: "chat-input__StyledSparkle",
|
|
114
|
-
componentId: "sc-
|
|
115
|
+
componentId: "sc-88c29886-4"
|
|
115
116
|
})([
|
|
116
117
|
`position:absolute;width:4px;height:4px;border-radius:50%;background:`,
|
|
117
118
|
`;box-shadow:0 0 6px `,
|
|
@@ -123,7 +124,7 @@ var StyledSparkle = styled.div.withConfig({
|
|
|
123
124
|
], ({ $color }) => $color, ({ $color }) => $color, ({ $left }) => $left, ({ $top }) => $top, sparkleFloat, ({ $delay }) => $delay);
|
|
124
125
|
var StyledTextarea = styled.textarea.withConfig({
|
|
125
126
|
displayName: "chat-input__StyledTextarea",
|
|
126
|
-
componentId: "sc-
|
|
127
|
+
componentId: "sc-88c29886-5"
|
|
127
128
|
})([
|
|
128
129
|
`position:relative;z-index:1;display:block;box-sizing:border-box;width:100%;resize:none;font-family:inherit;line-height:1.5;color:`,
|
|
129
130
|
`;background:`,
|
|
@@ -147,7 +148,7 @@ var StyledTextarea = styled.textarea.withConfig({
|
|
|
147
148
|
], theme.colors.primaryLight, theme.colors.primary, theme.colors.primaryLight, theme.colors.primary, theme.colors.primaryLight));
|
|
148
149
|
var StyledSendButton = styled(Button).withConfig({
|
|
149
150
|
displayName: "chat-input__StyledSendButton",
|
|
150
|
-
componentId: "sc-
|
|
151
|
+
componentId: "sc-88c29886-6"
|
|
151
152
|
})([`flex-shrink:0;`, `;min-height:0;position:relative;& svg,& .lucide{transition:none;position:absolute;inset:0;margin:auto;}`], formElementHeightStyles());
|
|
152
153
|
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
153
154
|
function LocalChatInput({ value, onValueChange, onSend, $loading, $glow = false, $glowColors, $maxRows, placeholder = "Ask AI Assistant...", "aria-label": ariaLabel = "Ask a question", ...props }, ref) {
|
|
@@ -247,7 +248,7 @@ function LocalChatInput({ value, onValueChange, onSend, $loading, $glow = false,
|
|
|
247
248
|
type: "submit",
|
|
248
249
|
disabled: loading || !hasContent,
|
|
249
250
|
"aria-label": loading ? "Loading response" : "Submit question",
|
|
250
|
-
children: loading ? /*#__PURE__*/ jsx(Spinner, {}) : /*#__PURE__*/ jsx(Icon, {
|
|
251
|
+
children: loading ? /*#__PURE__*/ jsx(Spinner, {}) : /*#__PURE__*/ jsx(Icon, { icon: ArrowUp })
|
|
251
252
|
})
|
|
252
253
|
]
|
|
253
254
|
});
|
package/dist/chat-launcher.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ChatContext } from "./chat-provider.js";
|
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { forwardRef, useContext } from "react";
|
|
8
8
|
import styled, { createGlobalStyle, css, keyframes } from "styled-components";
|
|
9
|
+
import { Sparkles } from "lucide-react";
|
|
9
10
|
//#region src/lib/chat-launcher.tsx
|
|
10
11
|
var GLOW_COLORS = [
|
|
11
12
|
"#cc5555",
|
|
@@ -21,7 +22,7 @@ var pulseGlow = keyframes([`0%,100%{opacity:0.5;filter:blur(16px);}50%{opacity:1
|
|
|
21
22
|
var conicStops = (colors) => [...colors, colors[0]].join(", ");
|
|
22
23
|
var StyledChatLauncher = styled.button.withConfig({
|
|
23
24
|
displayName: "chat-launcher__StyledChatLauncher",
|
|
24
|
-
componentId: "sc-
|
|
25
|
+
componentId: "sc-61e3ed78-0"
|
|
25
26
|
})([
|
|
26
27
|
``,
|
|
27
28
|
`;appearance:none;outline:none;cursor:pointer;box-sizing:border-box;height:30px;background:`,
|
|
@@ -68,7 +69,7 @@ function LocalChatLauncher({ children, $glow = false, $glowColors, onClick, "ari
|
|
|
68
69
|
}),
|
|
69
70
|
/*#__PURE__*/ jsx("span", {
|
|
70
71
|
className: "chat-launcher-inner",
|
|
71
|
-
children: children ?? /*#__PURE__*/ jsxs(Fragment, { children: [/*#__PURE__*/ jsx(Icon, {
|
|
72
|
+
children: children ?? /*#__PURE__*/ jsxs(Fragment, { children: [/*#__PURE__*/ jsx(Icon, { icon: Sparkles }), "Ask AI"] })
|
|
72
73
|
})
|
|
73
74
|
]
|
|
74
75
|
})] });
|
package/dist/chat-panel.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconSource } from './icon';
|
|
3
3
|
export type ChatPanelVariant = "drawer" | "inline" | "fullscreen";
|
|
4
4
|
export interface ChatPanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
5
|
children: React.ReactNode;
|
|
@@ -15,7 +15,8 @@ export interface ChatPanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
15
15
|
$width?: number;
|
|
16
16
|
/** Header title. Pass null to render no header text. */
|
|
17
17
|
$title?: React.ReactNode;
|
|
18
|
-
|
|
18
|
+
/** Header icon: an imported lucide component, or a rendered element. Pass null for none. */
|
|
19
|
+
$titleIcon?: IconSource | null;
|
|
19
20
|
/** Extra header controls (reset button, …), placed before the close button. */
|
|
20
21
|
$actions?: React.ReactNode;
|
|
21
22
|
$hideCloseButton?: boolean;
|
package/dist/chat-panel.js
CHANGED
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
import { mq } from "./utils/theme.js";
|
|
4
4
|
import { useLockBodyScroll } from "./utils/use-lock-body-scroll.js";
|
|
5
5
|
import { useBelowBreakpoint } from "./utils/use-media-query.js";
|
|
6
|
-
import { Icon } from "./icon.js";
|
|
6
|
+
import { Icon, renderIcon } from "./icon.js";
|
|
7
7
|
import { ChatContext } from "./chat-provider.js";
|
|
8
8
|
import { IconButton } from "./icon-button.js";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { forwardRef, useContext, useEffect, useRef } from "react";
|
|
11
11
|
import styled, { css } from "styled-components";
|
|
12
|
+
import { Sparkles, X } from "lucide-react";
|
|
12
13
|
//#region src/lib/chat-panel.tsx
|
|
13
14
|
var DEFAULT_WIDTH = 420;
|
|
14
15
|
var FOCUSABLE_SELECTOR = "a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
|
|
15
16
|
var StyledChatPanel = styled.div.withConfig({
|
|
16
17
|
displayName: "chat-panel__StyledChatPanel",
|
|
17
|
-
componentId: "sc-
|
|
18
|
+
componentId: "sc-82bb81a5-0"
|
|
18
19
|
})([
|
|
19
20
|
`display:flex;flex-direction:column;background:`,
|
|
20
21
|
`;color:`,
|
|
@@ -40,7 +41,7 @@ var StyledChatPanel = styled.div.withConfig({
|
|
|
40
41
|
`;}`
|
|
41
42
|
], $side, !$isVisible && css([`transform:translateX(`, `);opacity:0;visibility:hidden;transition-delay:0s,0s,0.3s;`], $side === "left" ? "-100%" : "100%"), mq("lg"), $width, $side === "left" ? "right" : "left", theme.colors.grayLight);
|
|
42
43
|
});
|
|
43
|
-
function LocalChatPanel({ children, $variant = "drawer", $side = "right", $width = DEFAULT_WIDTH, $title = "AI Assistant", $titleIcon =
|
|
44
|
+
function LocalChatPanel({ children, $variant = "drawer", $side = "right", $width = DEFAULT_WIDTH, $title = "AI Assistant", $titleIcon = Sparkles, $actions, $hideCloseButton, "aria-label": ariaLabel, ...props }, ref) {
|
|
44
45
|
const { isOpen, close, inputRef } = useContext(ChatContext);
|
|
45
46
|
const panelRef = useRef(null);
|
|
46
47
|
const isBelowLg = useBelowBreakpoint("lg");
|
|
@@ -145,14 +146,14 @@ function LocalChatPanel({ children, $variant = "drawer", $side = "right", $width
|
|
|
145
146
|
className: "chat-header",
|
|
146
147
|
children: [/*#__PURE__*/ jsxs("span", {
|
|
147
148
|
className: "chat-header-title",
|
|
148
|
-
children: [$titleIcon &&
|
|
149
|
+
children: [$titleIcon && renderIcon($titleIcon), $title !== null && /*#__PURE__*/ jsx("h3", { children: $title })]
|
|
149
150
|
}), /*#__PURE__*/ jsxs("span", {
|
|
150
151
|
className: "chat-header-actions",
|
|
151
152
|
children: [$actions, isOverlay && !$hideCloseButton && /*#__PURE__*/ jsx(IconButton, {
|
|
152
153
|
onClick: () => close(),
|
|
153
154
|
"aria-label": "Close chat",
|
|
154
155
|
title: "Close chat",
|
|
155
|
-
children: /*#__PURE__*/ jsx(Icon, {
|
|
156
|
+
children: /*#__PURE__*/ jsx(Icon, { icon: X })
|
|
156
157
|
})]
|
|
157
158
|
})]
|
|
158
159
|
}), children]
|
package/dist/dropzone.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconSource } from './icon';
|
|
3
3
|
export type DropzoneRejectionReason = "type" | "size" | "count";
|
|
4
4
|
export interface DropzoneRejection {
|
|
5
5
|
file: File;
|
|
@@ -12,8 +12,8 @@ export interface DropzoneProps extends Omit<React.InputHTMLAttributes<HTMLInputE
|
|
|
12
12
|
$browse?: string;
|
|
13
13
|
/** Optional smaller hint line (accepted types / limits). */
|
|
14
14
|
$hint?: string;
|
|
15
|
-
/**
|
|
16
|
-
$icon?:
|
|
15
|
+
/** Icon shown in the rounded-square tile: an imported lucide component, or a rendered element. */
|
|
16
|
+
$icon?: IconSource;
|
|
17
17
|
/** Compact, flush variant: horizontal layout, tighter padding, and a
|
|
18
18
|
transparent background so it sits on whatever surface it's embedded in
|
|
19
19
|
(a form row, modal, or list) next to regular inputs. */
|
package/dist/dropzone.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { mq } from "./utils/theme.js";
|
|
4
4
|
import { alpha, resetButton } from "./utils/mixins.js";
|
|
5
|
-
import { Icon } from "./icon.js";
|
|
5
|
+
import { Icon, renderIcon } from "./icon.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 { File, FileUp, X } from "lucide-react";
|
|
9
10
|
//#region src/lib/dropzone.tsx
|
|
10
11
|
/** Matches a file against an `accept` string (".pdf,image/*,text/plain"),
|
|
11
12
|
mirroring the native file-picker filter for dropped files. */ var matchesAccept = (file, accept) => {
|
|
@@ -18,7 +19,7 @@ mirroring the native file-picker filter for dropped files. */ var matchesAccept
|
|
|
18
19
|
return file.type.toLowerCase() === entry;
|
|
19
20
|
});
|
|
20
21
|
};
|
|
21
|
-
function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $icon =
|
|
22
|
+
function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $icon = FileUp, $inline, $maxFiles, $maxBytes, onFilesChange, onFilesRejected, accept, multiple, disabled, ...rest }, ref) {
|
|
22
23
|
const [items, setItems] = useState([]);
|
|
23
24
|
const [dragOver, setDragOver] = useState(false);
|
|
24
25
|
const inputRef = useRef(null);
|
|
@@ -111,7 +112,7 @@ function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $ic
|
|
|
111
112
|
children: [
|
|
112
113
|
/*#__PURE__*/ jsx(StyledDropIcon, {
|
|
113
114
|
$inline,
|
|
114
|
-
children:
|
|
115
|
+
children: renderIcon($icon)
|
|
115
116
|
}),
|
|
116
117
|
/*#__PURE__*/ jsxs(StyledDropPrompt, {
|
|
117
118
|
$inline,
|
|
@@ -141,12 +142,12 @@ function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $ic
|
|
|
141
142
|
children: [item.previewUrl ? /*#__PURE__*/ jsx("img", {
|
|
142
143
|
src: item.previewUrl,
|
|
143
144
|
alt: item.file.name
|
|
144
|
-
}) : /*#__PURE__*/ jsxs(StyledThumbFile, { children: [/*#__PURE__*/ jsx(Icon, {
|
|
145
|
+
}) : /*#__PURE__*/ jsxs(StyledThumbFile, { children: [/*#__PURE__*/ jsx(Icon, { icon: File }), /*#__PURE__*/ jsx("span", { children: item.file.name })] }), /*#__PURE__*/ jsx(StyledThumbRemove, {
|
|
145
146
|
type: "button",
|
|
146
147
|
"aria-label": `Remove ${item.file.name}`,
|
|
147
148
|
onClick: () => removeItem(item.key),
|
|
148
149
|
disabled,
|
|
149
|
-
children: /*#__PURE__*/ jsx(Icon, {
|
|
150
|
+
children: /*#__PURE__*/ jsx(Icon, { icon: X })
|
|
150
151
|
})]
|
|
151
152
|
}, item.key)) })
|
|
152
153
|
] });
|
|
@@ -154,11 +155,11 @@ function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $ic
|
|
|
154
155
|
var Dropzone = /*#__PURE__*/ forwardRef(LocalDropzone);
|
|
155
156
|
var StyledDropzoneWrapper = styled.div.withConfig({
|
|
156
157
|
displayName: "dropzone__StyledDropzoneWrapper",
|
|
157
|
-
componentId: "sc-
|
|
158
|
+
componentId: "sc-1391bc72-0"
|
|
158
159
|
})([`display:flex;flex-direction:column;gap:12px;width:100%;`]);
|
|
159
160
|
var StyledDropzone = styled.button.withConfig({
|
|
160
161
|
displayName: "dropzone__StyledDropzone",
|
|
161
|
-
componentId: "sc-
|
|
162
|
+
componentId: "sc-1391bc72-1"
|
|
162
163
|
})([
|
|
163
164
|
``,
|
|
164
165
|
`;font-family:inherit;display:flex;flex-direction:`,
|
|
@@ -183,7 +184,7 @@ var StyledDropzone = styled.button.withConfig({
|
|
|
183
184
|
], 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);
|
|
184
185
|
var StyledDropIcon = styled.span.withConfig({
|
|
185
186
|
displayName: "dropzone__StyledDropIcon",
|
|
186
|
-
componentId: "sc-
|
|
187
|
+
componentId: "sc-1391bc72-2"
|
|
187
188
|
})([
|
|
188
189
|
`display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:`,
|
|
189
190
|
`;height:`,
|
|
@@ -197,7 +198,7 @@ var StyledDropIcon = styled.span.withConfig({
|
|
|
197
198
|
], ({ $inline }) => $inline ? "32px" : "44px", ({ $inline }) => $inline ? "32px" : "44px", ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.primary, ({ $inline }) => $inline ? "18px" : "22px", ({ $inline }) => $inline ? "18px" : "22px");
|
|
198
199
|
var StyledDropPrompt = styled.span.withConfig({
|
|
199
200
|
displayName: "dropzone__StyledDropPrompt",
|
|
200
|
-
componentId: "sc-
|
|
201
|
+
componentId: "sc-1391bc72-3"
|
|
201
202
|
})([
|
|
202
203
|
`display:flex;flex-direction:`,
|
|
203
204
|
`;flex-wrap:wrap;align-items:baseline;gap:`,
|
|
@@ -209,7 +210,7 @@ var StyledDropPrompt = styled.span.withConfig({
|
|
|
209
210
|
], ({ $inline }) => $inline ? "row" : "column", ({ $inline }) => $inline ? "0 6px" : "2px", ({ theme }) => theme.fontSizes.text.xs, ({ theme }) => theme.lineHeights.text.xs, ({ theme }) => theme.colors.dark, ({ theme }) => theme.colors.grayDark);
|
|
210
211
|
var StyledDropHint = styled.span.withConfig({
|
|
211
212
|
displayName: "dropzone__StyledDropHint",
|
|
212
|
-
componentId: "sc-
|
|
213
|
+
componentId: "sc-1391bc72-4"
|
|
213
214
|
})([
|
|
214
215
|
`font-family:inherit;font-size:`,
|
|
215
216
|
`;line-height:`,
|
|
@@ -219,11 +220,11 @@ var StyledDropHint = styled.span.withConfig({
|
|
|
219
220
|
], ({ theme }) => theme.fontSizes.small.xs, ({ theme }) => theme.lineHeights.small.xs, ({ theme }) => theme.colors.gray, ({ $inline }) => $inline && css([`margin-left:auto;`]));
|
|
220
221
|
var StyledThumbs = styled.div.withConfig({
|
|
221
222
|
displayName: "dropzone__StyledThumbs",
|
|
222
|
-
componentId: "sc-
|
|
223
|
+
componentId: "sc-1391bc72-5"
|
|
223
224
|
})([`display:grid;grid-template-columns:repeat(auto-fill,72px);gap:10px;`, `{grid-template-columns:repeat(auto-fill,84px);}`], mq("sm"));
|
|
224
225
|
var StyledThumb = styled.div.withConfig({
|
|
225
226
|
displayName: "dropzone__StyledThumb",
|
|
226
|
-
componentId: "sc-
|
|
227
|
+
componentId: "sc-1391bc72-6"
|
|
227
228
|
})([
|
|
228
229
|
`position:relative;width:72px;height:72px;border-radius:`,
|
|
229
230
|
`;overflow:hidden;border:solid 1px `,
|
|
@@ -233,7 +234,7 @@ var StyledThumb = styled.div.withConfig({
|
|
|
233
234
|
], ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.light, mq("sm"));
|
|
234
235
|
var StyledThumbFile = styled.span.withConfig({
|
|
235
236
|
displayName: "dropzone__StyledThumbFile",
|
|
236
|
-
componentId: "sc-
|
|
237
|
+
componentId: "sc-1391bc72-7"
|
|
237
238
|
})([
|
|
238
239
|
`display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;width:100%;height:100%;padding:6px;color:`,
|
|
239
240
|
`;& svg{width:20px;height:20px;color:`,
|
|
@@ -241,7 +242,7 @@ var StyledThumbFile = styled.span.withConfig({
|
|
|
241
242
|
], ({ theme }) => theme.colors.grayDark, ({ theme }) => theme.colors.primary);
|
|
242
243
|
var StyledThumbRemove = styled.button.withConfig({
|
|
243
244
|
displayName: "dropzone__StyledThumbRemove",
|
|
244
|
-
componentId: "sc-
|
|
245
|
+
componentId: "sc-1391bc72-8"
|
|
245
246
|
})([
|
|
246
247
|
``,
|
|
247
248
|
`;position:absolute;top:4px;right:4px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;color:#ffffff;background:`,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IconName as LucideDynamicName } from 'lucide-react/dynamic';
|
|
2
|
+
import { icons } from 'lucide-react';
|
|
3
|
+
/**
|
|
4
|
+
* A lucide icon referenced by name: the PascalCase export name
|
|
5
|
+
* (`"ArrowRight"`) or lucide's own kebab-case id (`"arrow-right"`).
|
|
6
|
+
*/
|
|
7
|
+
export type IconName = keyof typeof icons | LucideDynamicName;
|
|
8
|
+
export interface DynamicIconProps {
|
|
9
|
+
/** The icon, by name. An unknown name renders nothing. */
|
|
10
|
+
name: IconName;
|
|
11
|
+
color?: string;
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
"aria-label"?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Renders a lucide icon chosen at runtime (CMS content, user settings). The
|
|
18
|
+
* glyph is fetched on demand through `lucide-react/dynamic`, so it appears
|
|
19
|
+
* after hydration once its chunk has loaded, and never in server-rendered
|
|
20
|
+
* HTML. For any icon known when the code is written, use
|
|
21
|
+
* `<Icon icon={Glyph} />` from the main entry instead. In a `$icon`-style
|
|
22
|
+
* prop, pass it as an element: `$icon={<DynamicIcon name={n} />}`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function DynamicIcon({ name, "aria-label": ariaLabel, ...props }: DynamicIconProps): import("react").JSX.Element | null;
|