cherry-styled-components 0.2.16 → 0.2.18

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 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.
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-20594240-0"
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-20594240-1"
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-20594240-2"
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-20594240-3"
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-20594240-4"
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, { name: "ChevronDown" })
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 { Icon } from './icon';
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
- /** Lucide icon shown while no picture is selected. */
8
- $icon?: React.ComponentProps<typeof Icon>["name"];
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. */
@@ -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 = "User", $maxBytes, "aria-label": ariaLabel = "Upload profile picture", onFileChange, onFileRejected, accept = "image/*", disabled, ...rest }, ref) {
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
- }) : /*#__PURE__*/ jsx(Icon, { name: $icon })
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, { name: "X" })
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-758cb640-0"
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-758cb640-1"
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-758cb640-2"
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 { IconProps } from './icon';
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?: IconProps;
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 { Icon } from "./icon.js";
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-d3a5da79-0"
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 = "User", $color, ...props }, ref) {
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 : /*#__PURE__*/ jsx(Icon, {
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 { IconProps } from './icon';
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?: IconProps;
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 { Icon } from "./icon.js";
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: "CircleAlert",
73
- info: "Info",
74
- warning: "TriangleAlert",
75
- danger: "OctagonAlert",
76
- success: "Check"
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-84e10f5e-0"
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 iconName = $icon ?? ($type ? calloutIcons[$type] : void 0);
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 && iconName && /*#__PURE__*/ jsx("span", {
108
+ children: [!$hideIcon && icon && /*#__PURE__*/ jsx("span", {
108
109
  className: "callout-icon",
109
- children: /*#__PURE__*/ jsx(Icon, {
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
@@ -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-d9366e15-0"
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-d9366e15-1"
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-d9366e15-2"
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-d9366e15-3"
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-d9366e15-4"
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-d9366e15-5"
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-d9366e15-6"
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, { name: "ArrowUp" })
251
+ children: loading ? /*#__PURE__*/ jsx(Spinner, {}) : /*#__PURE__*/ jsx(Icon, { icon: ArrowUp })
251
252
  })
252
253
  ]
253
254
  });
@@ -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-64539cc0-0"
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, { name: "Sparkles" }), "Ask AI"] })
72
+ children: children ?? /*#__PURE__*/ jsxs(Fragment, { children: [/*#__PURE__*/ jsx(Icon, { icon: Sparkles }), "Ask AI"] })
72
73
  })
73
74
  ]
74
75
  })] });
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
- import { IconProps } from './icon';
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
- $titleIcon?: IconProps | null;
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;
@@ -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-701cc462-0"
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 = "Sparkles", $actions, $hideCloseButton, "aria-label": ariaLabel, ...props }, ref) {
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 && /*#__PURE__*/ jsx(Icon, { name: $titleIcon }), $title !== null && /*#__PURE__*/ jsx("h3", { children: $title })]
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, { name: "X" })
156
+ children: /*#__PURE__*/ jsx(Icon, { icon: X })
156
157
  })]
157
158
  })]
158
159
  }), children]
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
- import { Icon } from './icon';
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
- /** Lucide icon shown in the rounded-square tile. */
16
- $icon?: React.ComponentProps<typeof Icon>["name"];
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 = "FileUp", $inline, $maxFiles, $maxBytes, onFilesChange, onFilesRejected, accept, multiple, disabled, ...rest }, ref) {
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: /*#__PURE__*/ jsx(Icon, { name: $icon })
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, { name: "File" }), /*#__PURE__*/ jsx("span", { children: item.file.name })] }), /*#__PURE__*/ jsx(StyledThumbRemove, {
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, { name: "X" })
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-a5a0875f-0"
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-a5a0875f-1"
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-a5a0875f-2"
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-a5a0875f-3"
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-a5a0875f-4"
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-a5a0875f-5"
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-a5a0875f-6"
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-a5a0875f-7"
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-a5a0875f-8"
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;
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ "use client";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { DynamicIcon as DynamicIcon$1, iconNames } from "lucide-react/dynamic";
5
+ //#region src/lib/icon-dynamic.tsx
6
+ var KEBAB_NAMES = new Set(iconNames);
7
+ function toPascal(name) {
8
+ return name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
9
+ }
10
+ var KEBAB_BY_PASCAL = new Map(iconNames.map((name) => [toPascal(name), name]));
11
+ function resolveIconName(name) {
12
+ if (KEBAB_NAMES.has(name)) return name;
13
+ return KEBAB_BY_PASCAL.get(toPascal(name)) ?? null;
14
+ }
15
+ /**
16
+ * Renders a lucide icon chosen at runtime (CMS content, user settings). The
17
+ * glyph is fetched on demand through `lucide-react/dynamic`, so it appears
18
+ * after hydration once its chunk has loaded, and never in server-rendered
19
+ * HTML. For any icon known when the code is written, use
20
+ * `<Icon icon={Glyph} />` from the main entry instead. In a `$icon`-style
21
+ * prop, pass it as an element: `$icon={<DynamicIcon name={n} />}`.
22
+ */ function DynamicIcon({ name, "aria-label": ariaLabel, ...props }) {
23
+ const iconName = resolveIconName(name);
24
+ if (!iconName) return null;
25
+ return /*#__PURE__*/ jsx(DynamicIcon$1, {
26
+ name: iconName,
27
+ ...props,
28
+ "aria-label": ariaLabel,
29
+ "aria-hidden": !ariaLabel,
30
+ role: ariaLabel ? "img" : void 0
31
+ });
32
+ }
33
+ //#endregion
34
+ export { DynamicIcon };
package/dist/icon.d.ts CHANGED
@@ -1,11 +1,45 @@
1
- import { icons } from 'lucide-react';
2
- export type IconProps = keyof typeof icons;
3
- interface Props {
4
- name: IconProps;
1
+ import { ComponentType, ReactElement } from 'react';
2
+ /**
3
+ * The props Cherry hands to an icon component. Every `lucide-react` export
4
+ * satisfies this, and so does any SVG component that takes a `size`.
5
+ */
6
+ export interface IconGlyphProps {
7
+ size?: number;
8
+ color?: string;
9
+ className?: string;
10
+ "aria-label"?: string;
11
+ "aria-hidden"?: boolean;
12
+ role?: "img";
13
+ }
14
+ /**
15
+ * An icon component: `import { ArrowRight } from "lucide-react"`, or a
16
+ * component of your own that accepts `IconGlyphProps`.
17
+ */
18
+ export type IconComponent = ComponentType<IconGlyphProps>;
19
+ /**
20
+ * What a component's `$icon`-style prop accepts: an `IconComponent`, which
21
+ * the component renders through `Icon` at the size it chooses, or a rendered
22
+ * element such as `<DynamicIcon name={n} />`, which is used as given.
23
+ */
24
+ export type IconSource = IconComponent | ReactElement;
25
+ export interface IconProps {
26
+ /** An imported lucide component, or any component taking `IconGlyphProps`. */
27
+ icon: IconComponent;
5
28
  color?: string;
6
29
  size?: number;
7
30
  className?: string;
8
31
  "aria-label"?: string;
9
32
  }
10
- declare const Icon: ({ name, color, size, className, "aria-label": ariaLabel, }: Props) => import("react").JSX.Element | null;
33
+ /**
34
+ * Renders one icon component. It costs exactly that glyph and renders on the
35
+ * server. Decorative unless labelled; a labelled glyph is announced as an
36
+ * image. For an icon chosen at runtime, see `DynamicIcon` in the
37
+ * `cherry-styled-components/dynamic` subpath.
38
+ */
39
+ declare const Icon: ({ icon: Glyph, color, size, className, "aria-label": ariaLabel, }: IconProps) => import("react").JSX.Element;
40
+ /**
41
+ * Renders an `IconSource`: an element as given, a component through `Icon`
42
+ * with `props`. For components that forward a `$icon`-style prop.
43
+ */
44
+ export declare function renderIcon(source: IconSource, props?: Omit<IconProps, "icon">): ReactElement;
11
45
  export { Icon };
package/dist/icon.js CHANGED
@@ -1,17 +1,29 @@
1
+ "use client";
2
+ "use client";
1
3
  import { jsx } from "react/jsx-runtime";
2
- import { icons } from "lucide-react";
4
+ import { isValidElement } from "react";
3
5
  //#region src/lib/icon.tsx
4
- var Icon = ({ name, color, size, className, "aria-label": ariaLabel }) => {
5
- const LucideIcon = icons[name];
6
- if (!LucideIcon) return null;
7
- return /*#__PURE__*/ jsx(LucideIcon, {
8
- color,
9
- size,
10
- className,
11
- "aria-label": ariaLabel,
12
- "aria-hidden": !ariaLabel,
13
- role: ariaLabel ? "img" : void 0
6
+ /**
7
+ * Renders one icon component. It costs exactly that glyph and renders on the
8
+ * server. Decorative unless labelled; a labelled glyph is announced as an
9
+ * image. For an icon chosen at runtime, see `DynamicIcon` in the
10
+ * `cherry-styled-components/dynamic` subpath.
11
+ */ var Icon = ({ icon: Glyph, color, size, className, "aria-label": ariaLabel }) => /*#__PURE__*/ jsx(Glyph, {
12
+ color,
13
+ size,
14
+ className,
15
+ "aria-label": ariaLabel,
16
+ "aria-hidden": !ariaLabel,
17
+ role: ariaLabel ? "img" : void 0
18
+ });
19
+ /**
20
+ * Renders an `IconSource`: an element as given, a component through `Icon`
21
+ * with `props`. For components that forward a `$icon`-style prop.
22
+ */ function renderIcon(source, props) {
23
+ return /*#__PURE__*/ isValidElement(source) ? source : /*#__PURE__*/ jsx(Icon, {
24
+ icon: source,
25
+ ...props
14
26
  });
15
- };
27
+ }
16
28
  //#endregion
17
- export { Icon };
29
+ export { Icon, renderIcon };
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { useOnClickOutside } from "./utils/use-on-click-outside.js";
8
8
  import { CherryThemeProvider, ThemeContext } from "./styled-components/theme-provider.js";
9
9
  import { ClientThemeProvider } from "./styled-components/client-theme-provider.js";
10
10
  import { createThemeInitScript, resolveTheme, themeInitScript } from "./styled-components/theme-init.js";
11
- import { Icon } from "./icon.js";
11
+ import { Icon, renderIcon } from "./icon.js";
12
12
  import { Accordion } from "./accordion.js";
13
13
  import { Avatar } from "./avatar.js";
14
14
  import { Dropzone, matchesAccept } from "./dropzone.js";
@@ -44,4 +44,4 @@ import { Textarea } from "./textarea.js";
44
44
  import { ThemeToggle } from "./theme-toggle.js";
45
45
  import { StyledNotificationItem, StyledNotifications, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, useToastNotifications } from "./toast.js";
46
46
  import { Toggle } from "./toggle.js";
47
- export { Accordion, Avatar, AvatarDropzone, Box, Button, Callout, ChatContext, ChatInput, ChatLauncher, ChatMessage, ChatMessageList, ChatPanel, ChatProvider, ChatSource, ChatSources, ChatTyping, CherryThemeProvider, ClientThemeProvider, Col, Container, Dropzone, Flex, GlobalStyles, Grid, Icon, IconButton, Input, MaxWidth, Modal, Password, Prose, Range, Select, Space, Spinner, StyledIconWrapper, StyledInputWrapper, StyledLabel, StyledNotificationItem, StyledNotifications, TabContent, Tabs, Textarea, ThemeContext, ThemeToggle, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, Toggle, alpha, breakpoints, buttonStyles, chatTextStyles, colors, colorsDark, createThemeInitScript, createTypographyStyle, darkFilledTextRule, errorInteractiveStyles, filledTextColor, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, iconButtonStyles, interactiveStyles, lineHeights, matchesAccept, mq, proseStyles, resetButton, resetInput, resolveShowcaseCommand, resolveTheme, shade, shadows, shadowsDark, showcaseCommands, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark, themeInitScript, thinScrollbar, tint, useBelowBreakpoint, useChat, useLockBodyScroll, useMediaQuery, useOnClickOutside, useToastNotifications };
47
+ export { Accordion, Avatar, AvatarDropzone, Box, Button, Callout, ChatContext, ChatInput, ChatLauncher, ChatMessage, ChatMessageList, ChatPanel, ChatProvider, ChatSource, ChatSources, ChatTyping, CherryThemeProvider, ClientThemeProvider, Col, Container, Dropzone, Flex, GlobalStyles, Grid, Icon, IconButton, Input, MaxWidth, Modal, Password, Prose, Range, Select, Space, Spinner, StyledIconWrapper, StyledInputWrapper, StyledLabel, StyledNotificationItem, StyledNotifications, TabContent, Tabs, Textarea, ThemeContext, ThemeToggle, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, Toggle, alpha, breakpoints, buttonStyles, chatTextStyles, colors, colorsDark, createThemeInitScript, createTypographyStyle, darkFilledTextRule, errorInteractiveStyles, filledTextColor, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, iconButtonStyles, interactiveStyles, lineHeights, matchesAccept, mq, proseStyles, renderIcon, resetButton, resetInput, resolveShowcaseCommand, resolveTheme, shade, shadows, shadowsDark, showcaseCommands, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark, themeInitScript, thinScrollbar, tint, useBelowBreakpoint, useChat, useLockBodyScroll, useMediaQuery, useOnClickOutside, useToastNotifications };
package/dist/input.js CHANGED
@@ -5,10 +5,11 @@ import { Icon } 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 { CalendarDays, Check } from "lucide-react";
8
9
  //#region src/lib/input.tsx
9
10
  var StyledInputWrapper = styled.span.withConfig({
10
11
  displayName: "input__StyledInputWrapper",
11
- componentId: "sc-5352dea9-0"
12
+ componentId: "sc-8a4d191a-0"
12
13
  })([
13
14
  `display:inline-flex;flex-wrap:`,
14
15
  `;align-items:center;`,
@@ -20,7 +21,7 @@ var StyledInputWrapper = styled.span.withConfig({
20
21
  ], ({ type }) => type === "checkbox" || type === "radio" ? "nowrap" : "wrap", ({ $label }) => $label && css([`gap:5px;align-items:flex-start;align-content:flex-start;`]), ({ $size }) => $size === "small" ? "14px" : "17px", ({ $size }) => $size === "small" ? "18px" : "24px", ({ $size }) => $size === "small" ? "18px" : "24px", ({ $fullWidth }) => fullWidthStyles($fullWidth));
21
22
  var StyledLabel = styled.label.withConfig({
22
23
  displayName: "input__StyledLabel",
23
- componentId: "sc-5352dea9-1"
24
+ componentId: "sc-8a4d191a-1"
24
25
  })([
25
26
  `display:inline-block;color:`,
26
27
  `;font-size:`,
@@ -29,7 +30,7 @@ var StyledLabel = styled.label.withConfig({
29
30
  ], ({ theme }) => theme.colors.grayDark, ({ theme }) => theme.fontSizes.small.lg, ({ theme }) => theme.lineHeights.small.lg);
30
31
  var StyledInput = styled.input.withConfig({
31
32
  displayName: "input__StyledInput",
32
- componentId: "sc-5352dea9-2"
33
+ componentId: "sc-8a4d191a-2"
33
34
  })([
34
35
  ``,
35
36
  `;`,
@@ -38,7 +39,7 @@ var StyledInput = styled.input.withConfig({
38
39
  `;background:`,
39
40
  `;border:solid 2px `,
40
41
  `;box-shadow:0 0 0 0px `,
41
- `;transition:all 0.3s ease;word-break:keep-all;white-space:nowrap;display:inline-flex;&::-webkit-datetime-edit{padding:0;margin:0;vertical-align:middle;}&::-webkit-datetime-edit-fields-wrapper{padding:4px 0;margin:0;vertical-align:middle;}&::-webkit-calendar-picker-indicator{background:transparent;cursor:pointer;position:absolute;right:15px;top:50%;transform:translateY(-50%);width:24px;height:24px;}&::-webkit-datetime-edit-text{color:`,
42
+ `;transition:all 0.3s ease;word-break:keep-all;white-space:nowrap;display:inline-flex;&::-webkit-datetime-edit{padding:0;margin:0;vertical-align:middle;}&::-webkit-datetime-edit-fields-wrapper{padding:4px 0;margin:0;vertical-align:middle;}&::-webkit-date-and-time-value{text-align:left;margin:0;}&::-webkit-calendar-picker-indicator{background:transparent;cursor:pointer;position:absolute;right:15px;top:50%;transform:translateY(-50%);width:24px;height:24px;}&::-webkit-datetime-edit-text{color:`,
42
43
  `;}&::-webkit-datetime-edit-month-field{&:focus{background:`,
43
44
  `;color:`,
44
45
  `;border-radius:4px;}}&::-webkit-datetime-edit-day-field{&:focus{background:`,
@@ -85,7 +86,7 @@ var StyledInput = styled.input.withConfig({
85
86
  `, ({ $fullWidth }) => fullWidthStyles($fullWidth));
86
87
  var StyledIconWrapper = styled.span.withConfig({
87
88
  displayName: "input__StyledIconWrapper",
88
- componentId: "sc-5352dea9-3"
89
+ componentId: "sc-8a4d191a-3"
89
90
  })([
90
91
  `display:inline-flex;position:relative;line-height:0;min-width:fit-content;& em{display:block;border-radius:50%;background:`,
91
92
  `;}& svg,& em{object-fit:contain;position:absolute;top:50%;left:50%;color:`,
@@ -93,7 +94,7 @@ var StyledIconWrapper = styled.span.withConfig({
93
94
  ], ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primary);
94
95
  var StyledRadioCheckboxInput = styled.input.withConfig({
95
96
  displayName: "input__StyledRadioCheckboxInput",
96
- componentId: "sc-5352dea9-4"
97
+ componentId: "sc-8a4d191a-4"
97
98
  })([
98
99
  ``,
99
100
  `;display:inline-block;background:`,
@@ -178,7 +179,7 @@ var StyledRadioCheckboxInput = styled.input.withConfig({
178
179
  });
179
180
  var StyledCustomIconWrapper = styled.span.withConfig({
180
181
  displayName: "input__StyledCustomIconWrapper",
181
- componentId: "sc-5352dea9-5"
182
+ componentId: "sc-8a4d191a-5"
182
183
  })([
183
184
  `position:relative;`,
184
185
  `;& svg{position:absolute;top:50%;transform:translateY(-50%);pointer-events:none;width:24px;height:24px;object-fit:contain;color:`,
@@ -195,7 +196,7 @@ function LocalInput({ ...props }, ref) {
195
196
  ...props,
196
197
  "aria-invalid": props.$error || void 0,
197
198
  ref
198
- }), !props.disabled && props.type === "checkbox" ? /*#__PURE__*/ jsx(Icon, { name: "Check" }) : /*#__PURE__*/ jsx("em", {})] }), props.$label && /*#__PURE__*/ jsx(StyledLabel, {
199
+ }), !props.disabled && props.type === "checkbox" ? /*#__PURE__*/ jsx(Icon, { icon: Check }) : /*#__PURE__*/ jsx("em", {})] }), props.$label && /*#__PURE__*/ jsx(StyledLabel, {
199
200
  htmlFor: props.id,
200
201
  children: props.$label
201
202
  })]
@@ -222,7 +223,7 @@ function LocalInput({ ...props }, ref) {
222
223
  }),
223
224
  props.$iconPosition === "right" && props.$icon && props.$icon,
224
225
  (props.type === "date" || props.type === "datetime-local" || props.type === "month" || props.type === "week" || props.type === "time") && /*#__PURE__*/ jsx(Icon, {
225
- name: "CalendarDays",
226
+ icon: CalendarDays,
226
227
  className: "icon-calendar"
227
228
  })
228
229
  ]
package/dist/modal.js CHANGED
@@ -9,6 +9,7 @@ import { IconButton } from "./icon-button.js";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
11
11
  import styled, { css, keyframes } from "styled-components";
12
+ import { X } from "lucide-react";
12
13
  import { createPortal } from "react-dom";
13
14
  //#region src/lib/modal.tsx
14
15
  var emptySubscribe = () => () => {};
@@ -21,7 +22,7 @@ var innerRiseIn = keyframes([`from{transform:translateY(40px);}to{transform:tran
21
22
  var innerSinkOut = keyframes([`from{transform:translateY(0);}to{transform:translateY(40px);}`]);
22
23
  var StyledModal = styled.div.withConfig({
23
24
  displayName: "modal__StyledModal",
24
- componentId: "sc-1bbfce8-0"
25
+ componentId: "sc-937855ae-0"
25
26
  })([
26
27
  `position:fixed;top:0;left:0;width:100%;height:100%;background:`,
27
28
  `;display:flex;justify-content:center;align-items:center;z-index:1010;animation:`,
@@ -35,11 +36,11 @@ var StyledModal = styled.div.withConfig({
35
36
  ], ({ theme }) => alpha(theme.colors.primary, 50), ({ $isClosing }) => $isClosing ? overlayFadeOut : overlayFadeIn, ({ $isClosing }) => $isClosing && css([`pointer-events:none;`]), ({ theme }) => theme.colors.light, ({ theme }) => theme.spacing.radius.lg, ({ $isClosing }) => $isClosing ? innerSinkOut : innerRiseIn, mq("lg"), ({ $width }) => $width && css([`max-width:`, `px;`], $width));
36
37
  var StyledModalClose = styled(IconButton).withConfig({
37
38
  displayName: "modal__StyledModalClose",
38
- componentId: "sc-1bbfce8-1"
39
+ componentId: "sc-937855ae-1"
39
40
  })([`position:absolute;top:20px;right:20px;z-index:10;`]);
40
41
  var StyledModalTitle = styled.h2.withConfig({
41
42
  displayName: "modal__StyledModalTitle",
42
- componentId: "sc-1bbfce8-2"
43
+ componentId: "sc-937855ae-2"
43
44
  })([
44
45
  `--divider-color:`,
45
46
  `;margin:0 0 15px 0;padding:0 0 15px 0;color:`,
@@ -48,7 +49,7 @@ var StyledModalTitle = styled.h2.withConfig({
48
49
  ], ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.dark, ({ theme }) => styledH5(theme));
49
50
  var StyledModalContent = styled.div.withConfig({
50
51
  displayName: "modal__StyledModalContent",
51
- componentId: "sc-1bbfce8-3"
52
+ componentId: "sc-937855ae-3"
52
53
  })([
53
54
  `max-height:calc(100svh - 200px);overflow-y:auto;padding:5px;margin:-5px;--divider-color:`,
54
55
  `;`,
@@ -101,7 +102,7 @@ function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton,
101
102
  onClick: closeModal,
102
103
  className: "modal-close",
103
104
  "aria-label": "Close Modal",
104
- children: /*#__PURE__*/ jsx(Icon, { name: "X" })
105
+ children: /*#__PURE__*/ jsx(Icon, { icon: X })
105
106
  })
106
107
  }),
107
108
  $title && /*#__PURE__*/ jsx(StyledModalTitle, {
package/dist/password.js CHANGED
@@ -7,6 +7,7 @@ import { Input } from "./input.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { forwardRef, useState } from "react";
9
9
  import styled, { css } from "styled-components";
10
+ import { Eye, EyeOff } from "lucide-react";
10
11
  //#region src/lib/password.tsx
11
12
  var passwordSizes = {
12
13
  small: {
@@ -27,7 +28,7 @@ var passwordSizes = {
27
28
  };
28
29
  var StyledPassword = styled.span.withConfig({
29
30
  displayName: "password__StyledPassword",
30
- componentId: "sc-b3beabaa-0"
31
+ componentId: "sc-ab5e6dd3-0"
31
32
  })([
32
33
  `position:relative;display:inline-flex;& input{padding-right:`,
33
34
  `;}`,
@@ -38,7 +39,7 @@ var StyledPassword = styled.span.withConfig({
38
39
  }, ({ $fullWidth }) => fullWidthStyles($fullWidth));
39
40
  var StyledPasswordReveal = styled.span.withConfig({
40
41
  displayName: "password__StyledPasswordReveal",
41
- componentId: "sc-b3beabaa-1"
42
+ componentId: "sc-ab5e6dd3-1"
42
43
  })([`position:absolute;bottom:0;display:flex;align-items:center;`, ``], ({ $size }) => {
43
44
  const { height, inset } = passwordSizes[$size ?? "default"];
44
45
  return css([
@@ -65,7 +66,7 @@ function LocalPassword({ ...props }, ref) {
65
66
  "aria-pressed": show,
66
67
  title: show ? "Hide password" : "Show password",
67
68
  onClick: () => setShow((prev) => !prev),
68
- children: /*#__PURE__*/ jsx(Icon, { name: show ? "EyeOff" : "Eye" })
69
+ children: /*#__PURE__*/ jsx(Icon, { icon: show ? EyeOff : Eye })
69
70
  })
70
71
  })]
71
72
  });
package/dist/select.js CHANGED
@@ -6,10 +6,11 @@ import { StyledInputWrapper, StyledLabel } from "./input.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { forwardRef } from "react";
8
8
  import styled from "styled-components";
9
+ import { ChevronDown } from "lucide-react";
9
10
  //#region src/lib/select.tsx
10
11
  var StyledSelect = styled.select.withConfig({
11
12
  displayName: "select__StyledSelect",
12
- componentId: "sc-65975d95-0"
13
+ componentId: "sc-ea1826c7-0"
13
14
  })([
14
15
  ``,
15
16
  `;`,
@@ -38,7 +39,7 @@ var StyledSelect = styled.select.withConfig({
38
39
  `, ({ $fullWidth }) => fullWidthStyles($fullWidth));
39
40
  var StyledIconWrapper = styled.span.withConfig({
40
41
  displayName: "select__StyledIconWrapper",
41
- componentId: "sc-65975d95-1"
42
+ componentId: "sc-ea1826c7-1"
42
43
  })([
43
44
  `position:relative;`,
44
45
  ` & svg{position:absolute;top:50%;right:15px;width:24px;height:24px;color:`,
@@ -59,7 +60,7 @@ function LocalSelect({ ...props }, ref) {
59
60
  "aria-invalid": props.$error || void 0,
60
61
  ref,
61
62
  children: props.children
62
- }), /*#__PURE__*/ jsx(Icon, { name: "ChevronDown" })]
63
+ }), /*#__PURE__*/ jsx(Icon, { icon: ChevronDown })]
63
64
  })]
64
65
  });
65
66
  }
package/dist/spinner.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { IconProps } from './icon';
1
+ import { IconComponent } from './icon';
2
2
  export interface SpinnerProps {
3
- /** Lucide icon to rotate. */
4
- name?: IconProps;
3
+ /** The icon to rotate: an imported lucide component. Defaults to `LoaderCircle`. */
4
+ icon?: IconComponent;
5
5
  color?: string;
6
6
  size?: number;
7
7
  className?: string;
8
8
  "aria-label"?: string;
9
9
  }
10
- declare const Spinner: ({ name, ...props }: SpinnerProps) => import("react").JSX.Element;
10
+ declare const Spinner: ({ icon, ...props }: SpinnerProps) => import("react").JSX.Element;
11
11
  export { Spinner };
package/dist/spinner.js CHANGED
@@ -3,18 +3,19 @@
3
3
  import { Icon } from "./icon.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import styled, { keyframes } from "styled-components";
6
+ import { LoaderCircle } from "lucide-react";
6
7
  //#region src/lib/spinner.tsx
7
8
  var spin = keyframes([`0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}`]);
8
9
  var StyledSpinner = styled(Icon).withConfig({
9
10
  displayName: "spinner__StyledSpinner",
10
- componentId: "sc-bb636095-0"
11
+ componentId: "sc-af2b088c-0"
11
12
  })([
12
13
  `color:`,
13
14
  `;animation:`,
14
15
  ` 1s linear infinite;@media (prefers-reduced-motion:reduce){animation:none;}`
15
16
  ], ({ theme }) => theme.colors.dark, spin);
16
- var Spinner = ({ name = "LoaderCircle", ...props }) => /*#__PURE__*/ jsx(StyledSpinner, {
17
- name,
17
+ var Spinner = ({ icon = LoaderCircle, ...props }) => /*#__PURE__*/ jsx(StyledSpinner, {
18
+ icon,
18
19
  ...props
19
20
  });
20
21
  //#endregion
@@ -6,10 +6,11 @@ import { Icon } from "./icon.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { forwardRef, useContext, useEffect } from "react";
8
8
  import styled, { css } from "styled-components";
9
+ import { MoonStar, Sun } from "lucide-react";
9
10
  //#region src/lib/theme-toggle.tsx
10
11
  var StyledThemeToggle = styled.button.withConfig({
11
12
  displayName: "theme-toggle__StyledThemeToggle",
12
- componentId: "sc-f8700a2a-0"
13
+ componentId: "sc-85f678d3-0"
13
14
  })([
14
15
  ``,
15
16
  ` `,
@@ -45,7 +46,7 @@ function LocalThemeToggle({ onClick, $shortcut = false, ...props }, ref) {
45
46
  onClick?.(event);
46
47
  },
47
48
  ref,
48
- children: [/*#__PURE__*/ jsx(Icon, { name: "Sun" }), /*#__PURE__*/ jsx(Icon, { name: "MoonStar" })]
49
+ children: [/*#__PURE__*/ jsx(Icon, { icon: Sun }), /*#__PURE__*/ jsx(Icon, { icon: MoonStar })]
49
50
  });
50
51
  }
51
52
  var ThemeToggle = /*#__PURE__*/ forwardRef(LocalThemeToggle);
package/dist/toast.js CHANGED
@@ -5,12 +5,13 @@ import { IconButton } from "./icon-button.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
7
7
  import styled, { css } from "styled-components";
8
+ import { CircleCheck, CircleX, Info, TriangleAlert, X } from "lucide-react";
8
9
  //#region src/lib/toast.tsx
9
10
  var statusIcons = {
10
- success: "CircleCheck",
11
- error: "CircleX",
12
- warning: "TriangleAlert",
13
- info: "Info"
11
+ success: CircleCheck,
12
+ error: CircleX,
13
+ warning: TriangleAlert,
14
+ info: Info
14
15
  };
15
16
  var EXIT_DURATION_MS = 400;
16
17
  var ToastNotificationsContext = /*#__PURE__*/ createContext({
@@ -52,11 +53,11 @@ function ToastNotificationsProvider({ children }) {
52
53
  }
53
54
  var StyledNotifications = styled.ul.withConfig({
54
55
  displayName: "toast__StyledNotifications",
55
- componentId: "sc-623506e7-0"
56
+ componentId: "sc-5ff21b00-0"
56
57
  })([`position:fixed;z-index:99999;margin:0;padding:0;list-style:none;left:20px;right:20px;pointer-events:none;`, ``], ({ $bottom }) => $bottom ? css([`bottom:20px;`]) : css([`top:20px;`]));
57
58
  var StyledNotificationItem = styled.li.withConfig({
58
59
  displayName: "toast__StyledNotificationItem",
59
- componentId: "sc-623506e7-1"
60
+ componentId: "sc-5ff21b00-1"
60
61
  })([
61
62
  `display:grid;grid-template-rows:0fr;justify-items:center;margin:0;padding:0;opacity:0;pointer-events:none;transform:translateY(`,
62
63
  `);transition:opacity 0.2s ease,transform 0.2s ease,grid-template-rows 0.25s ease 0.15s,margin 0.25s ease 0.15s;`,
@@ -126,7 +127,7 @@ function NotificationItem({ notification, $align, $bottom }) {
126
127
  children: [
127
128
  /*#__PURE__*/ jsx("span", {
128
129
  className: "status-icon",
129
- children: /*#__PURE__*/ jsx(Icon, { name: statusIcons[notification.color] || statusIcons.info })
130
+ children: /*#__PURE__*/ jsx(Icon, { icon: statusIcons[notification.color] ?? statusIcons.info })
130
131
  }),
131
132
  /*#__PURE__*/ jsx("span", {
132
133
  className: "message",
@@ -137,7 +138,7 @@ function NotificationItem({ notification, $align, $bottom }) {
137
138
  className: "close-button",
138
139
  "aria-label": "Dismiss notification",
139
140
  onClick: () => setPhase("exiting"),
140
- children: /*#__PURE__*/ jsx(Icon, { name: "X" })
141
+ children: /*#__PURE__*/ jsx(Icon, { icon: X })
141
142
  })
142
143
  ]
143
144
  })
package/dist/toggle.js CHANGED
@@ -8,11 +8,11 @@ import styled from "styled-components";
8
8
  //#region src/lib/toggle.tsx
9
9
  var StyledToggleWrapper = styled.span.withConfig({
10
10
  displayName: "toggle__StyledToggleWrapper",
11
- componentId: "sc-279a0aa6-0"
11
+ componentId: "sc-aa895e38-0"
12
12
  })([`display:inline-block;margin:auto 0;position:relative;vertical-align:middle;`]);
13
13
  var StyledFakeToggle = styled.span.withConfig({
14
14
  displayName: "toggle__StyledFakeToggle",
15
- componentId: "sc-279a0aa6-1"
15
+ componentId: "sc-aa895e38-1"
16
16
  })([
17
17
  `display:block;border:solid 2px `,
18
18
  `;background:`,
@@ -32,7 +32,7 @@ var StyledFakeToggle = styled.span.withConfig({
32
32
  }, ({ theme }) => theme.spacing.radius.xl, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.primary, ({ $size }) => $size === "big" ? "32px" : $size === "small" ? "18px" : "22px", ({ $size }) => $size === "big" ? "32px" : $size === "small" ? "18px" : "22px");
33
33
  var StyledToggle = styled.input.withConfig({
34
34
  displayName: "toggle__StyledToggle",
35
- componentId: "sc-279a0aa6-2"
35
+ componentId: "sc-aa895e38-2"
36
36
  })([
37
37
  ``,
38
38
  `;position:absolute;left:0;top:0;width:100%;height:100%;outline:none;z-index:10;&:checked ~ .fake-toggle{&::before{max-width:46px;background:`,
@@ -41,21 +41,11 @@ var StyledToggle = styled.input.withConfig({
41
41
  `;}&:focus:not([disabled]) ~ .fake-toggle{outline:none;border-color:`,
42
42
  `;box-shadow:0 0 0 4px `,
43
43
  `;}&:active:not([disabled]) ~ .fake-toggle{box-shadow:0 0 0 2px `,
44
- `;}`,
45
- ``
46
- ], resetButton, ({ theme }) => theme.colors.primaryLight, ({ $size }) => $size === "big" ? "25px" : $size === "small" ? "20px" : "25px", ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primaryLight, ({ theme }) => theme.colors.primaryLight, ({ disabled, theme }) => disabled && `cursor: not-allowed;
47
-
48
- & ~ .fake-toggle {
49
- border-color: ${theme.colors.gray};
50
-
51
- &::before {
52
- background: ${theme.colors.grayLight};
53
- }
54
-
55
- &::after {
56
- background: ${theme.colors.gray};
57
- }
58
- }`);
44
+ `;}&:disabled{cursor:not-allowed;}&:disabled ~ .fake-toggle,&:disabled:checked ~ .fake-toggle{border-color:`,
45
+ `;&::before{background:`,
46
+ `;}&::after{background:`,
47
+ `;}}`
48
+ ], resetButton, ({ theme }) => theme.colors.primaryLight, ({ $size }) => $size === "big" ? "25px" : $size === "small" ? "20px" : "25px", ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primaryLight, ({ theme }) => theme.colors.primaryLight, ({ theme }) => theme.colors.gray, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.gray);
59
49
  function LocalToggle({ type = "checkbox", ...props }, ref) {
60
50
  return /*#__PURE__*/ jsxs(StyledInputWrapper, {
61
51
  $fullWidth: props.$fullWidth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cherry-styled-components",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "Cherry is a design system for the modern web. Designed in Figma, built in React using Typescript.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -14,6 +14,10 @@
14
14
  "./next": {
15
15
  "types": "./dist/styled-components/registry.d.ts",
16
16
  "import": "./dist/styled-components/registry.js"
17
+ },
18
+ "./dynamic": {
19
+ "types": "./dist/icon-dynamic.d.ts",
20
+ "import": "./dist/icon-dynamic.js"
17
21
  }
18
22
  },
19
23
  "files": [
@@ -24,7 +28,7 @@
24
28
  "homepage": "https://cherry.al",
25
29
  "repository": "https://github.com/cherry-design-system/styled-components",
26
30
  "license": "MIT",
27
- "packageManager": "pnpm@11.21.0",
31
+ "packageManager": "pnpm@12.4.1",
28
32
  "engines": {
29
33
  "node": ">=18.0.0"
30
34
  },
@@ -48,33 +52,32 @@
48
52
  "format:check": "prettier --check .",
49
53
  "screenshots": "node scripts/screenshot-previews.cjs"
50
54
  },
51
- "dependencies": {
52
- "lucide-react": "^1.31.0"
53
- },
54
55
  "peerDependencies": {
56
+ "lucide-react": "^1.31.0",
55
57
  "react": "^18.0.0 || ^19.0.0",
56
58
  "react-dom": "^18.0.0 || ^19.0.0",
57
59
  "styled-components": "^6.0.0"
58
60
  },
59
61
  "devDependencies": {
60
- "@swc/plugin-styled-components": "^12.19.0",
61
- "@types/node": "^26.2.0",
62
- "@types/react": "^19.2.18",
63
- "@types/react-dom": "^19.2.4",
62
+ "@swc/plugin-styled-components": "^14.0.0",
63
+ "@types/node": "^26.4.1",
64
+ "@types/react": "^19.3.0",
65
+ "@types/react-dom": "^19.3.0",
64
66
  "@typescript/typescript6": "^6.0.2",
65
67
  "@vitejs/plugin-react-swc": "^4.3.3",
66
68
  "eslint-plugin-react-hooks": "^7.1.1",
67
- "eslint-plugin-react-refresh": "^0.5.4",
68
- "next": "^16.3.1",
69
- "playwright-core": "^1.62.1",
69
+ "eslint-plugin-react-refresh": "^0.5.6",
70
+ "lucide-react": "^1.44.0",
71
+ "next": "^16.3.4",
72
+ "playwright-core": "^1.63.0",
70
73
  "prettier": "^3.9.6",
71
- "react": "^19.2.8",
72
- "react-dom": "^19.2.8",
74
+ "react": "^19.3.0",
75
+ "react-dom": "^19.3.0",
73
76
  "rollup-plugin-preserve-directives": "^0.4.0",
74
- "sharp": "^0.35.3",
75
- "styled-components": "^6.5.2",
77
+ "sharp": "^0.35.4",
78
+ "styled-components": "^6.5.3",
76
79
  "typescript": "^7.0.2",
77
- "vite": "^8.2.1",
78
- "vite-plugin-dts": "^5.0.3"
80
+ "vite": "^8.3.0",
81
+ "vite-plugin-dts": "^5.1.0"
79
82
  }
80
83
  }