cherry-styled-components 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -28
- package/dist/avatar-dropzone.js +8 -8
- package/dist/avatar.d.ts +17 -0
- package/dist/avatar.js +68 -0
- package/dist/button.js +15 -12
- package/dist/callout.d.ts +13 -0
- package/dist/callout.js +121 -0
- package/dist/chat-input.d.ts +18 -0
- package/dist/chat-input.js +257 -0
- package/dist/chat-launcher.d.ts +10 -0
- package/dist/chat-launcher.js +78 -0
- package/dist/chat-message-list.d.ts +12 -0
- package/dist/chat-message-list.js +88 -0
- package/dist/chat-message.d.ts +16 -0
- package/dist/chat-message.js +56 -0
- package/dist/chat-panel.d.ts +25 -0
- package/dist/chat-panel.js +163 -0
- package/dist/chat-provider.d.ts +86 -0
- package/dist/chat-provider.js +295 -0
- package/dist/chat-showcase.d.ts +18 -0
- package/dist/chat-showcase.js +234 -0
- package/dist/chat-sources.d.ts +10 -0
- package/dist/chat-sources.js +41 -0
- package/dist/chat-typing.d.ts +7 -0
- package/dist/chat-typing.js +44 -0
- package/dist/dropzone.js +14 -14
- package/dist/icon-button.js +7 -7
- package/dist/index.d.ts +13 -0
- package/dist/index.js +18 -3
- package/dist/input.js +6 -6
- package/dist/modal.js +6 -6
- package/dist/prose.d.ts +17 -0
- package/dist/prose.js +75 -0
- package/dist/spinner.d.ts +11 -0
- package/dist/spinner.js +21 -0
- package/dist/styled-components/client-theme-provider.js +13 -3
- package/dist/tabs.js +6 -7
- package/dist/theme-toggle.js +5 -5
- package/dist/toast.d.ts +2 -2
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/mixins.d.ts +30 -0
- package/dist/utils/mixins.js +24 -3
- package/dist/utils/use-lock-body-scroll.d.ts +5 -0
- package/dist/utils/use-lock-body-scroll.js +25 -0
- package/dist/utils/use-media-query.d.ts +14 -0
- package/dist/utils/use-media-query.js +28 -0
- package/package.json +15 -14
package/dist/modal.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
3
|
import { mq } from "./utils/theme.js";
|
|
4
|
+
import { alpha } from "./utils/mixins.js";
|
|
4
5
|
import { styledH5, styledText } from "./utils/typography.js";
|
|
5
6
|
import { useOnClickOutside } from "./utils/use-on-click-outside.js";
|
|
6
7
|
import { Icon } from "./icon.js";
|
|
@@ -8,7 +9,6 @@ import { IconButton } from "./icon-button.js";
|
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
10
11
|
import styled, { css, keyframes } from "styled-components";
|
|
11
|
-
import { rgba } from "polished";
|
|
12
12
|
import { createPortal } from "react-dom";
|
|
13
13
|
//#region src/lib/modal.tsx
|
|
14
14
|
var emptySubscribe = () => () => {};
|
|
@@ -21,7 +21,7 @@ var innerRiseIn = keyframes([`from{transform:translateY(40px);}to{transform:tran
|
|
|
21
21
|
var innerSinkOut = keyframes([`from{transform:translateY(0);}to{transform:translateY(40px);}`]);
|
|
22
22
|
var StyledModal = styled.div.withConfig({
|
|
23
23
|
displayName: "modal__StyledModal",
|
|
24
|
-
componentId: "sc-
|
|
24
|
+
componentId: "sc-1bbfce8-0"
|
|
25
25
|
})([
|
|
26
26
|
`position:fixed;top:0;left:0;width:100%;height:100%;background:`,
|
|
27
27
|
`;display:flex;justify-content:center;align-items:center;z-index:1010;animation:`,
|
|
@@ -32,14 +32,14 @@ var StyledModal = styled.div.withConfig({
|
|
|
32
32
|
` 0.3s ease both;`,
|
|
33
33
|
`{max-width:500px;`,
|
|
34
34
|
`}}`
|
|
35
|
-
], ({ theme }) =>
|
|
35
|
+
], ({ 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
36
|
var StyledModalClose = styled(IconButton).withConfig({
|
|
37
37
|
displayName: "modal__StyledModalClose",
|
|
38
|
-
componentId: "sc-
|
|
38
|
+
componentId: "sc-1bbfce8-1"
|
|
39
39
|
})([`position:absolute;top:20px;right:20px;z-index:10;`]);
|
|
40
40
|
var StyledModalTitle = styled.h2.withConfig({
|
|
41
41
|
displayName: "modal__StyledModalTitle",
|
|
42
|
-
componentId: "sc-
|
|
42
|
+
componentId: "sc-1bbfce8-2"
|
|
43
43
|
})([
|
|
44
44
|
`--divider-color:`,
|
|
45
45
|
`;margin:0 0 15px 0;padding:0 0 15px 0;color:`,
|
|
@@ -48,7 +48,7 @@ var StyledModalTitle = styled.h2.withConfig({
|
|
|
48
48
|
], ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.dark, ({ theme }) => styledH5(theme));
|
|
49
49
|
var StyledModalContent = styled.div.withConfig({
|
|
50
50
|
displayName: "modal__StyledModalContent",
|
|
51
|
-
componentId: "sc-
|
|
51
|
+
componentId: "sc-1bbfce8-3"
|
|
52
52
|
})([
|
|
53
53
|
`max-height:calc(100svh - 200px);overflow-y:auto;padding:5px;margin:-5px;--divider-color:`,
|
|
54
54
|
`;`,
|
package/dist/prose.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { Theme } from './utils';
|
|
3
|
+
export interface ProseProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
/** Tightens the vertical rhythm for dense contexts such as chat bubbles. */
|
|
6
|
+
$compact?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Styles for rendered markdown: links, lists, tables, code, media and
|
|
10
|
+
* headings. Exported so it can be applied to an element that is already
|
|
11
|
+
* styled, rather than wrapping it in another <div>.
|
|
12
|
+
*/
|
|
13
|
+
export declare const proseStyles: (theme: Theme, $compact?: boolean) => import('styled-components').RuleSet<NoInfer<{
|
|
14
|
+
theme: Theme;
|
|
15
|
+
}>>;
|
|
16
|
+
declare const Prose: React.ForwardRefExoticComponent<ProseProps & React.RefAttributes<HTMLDivElement>>;
|
|
17
|
+
export { Prose };
|
package/dist/prose.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { alpha, thinScrollbar } from "./utils/mixins.js";
|
|
4
|
+
import { styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledSmall, styledText } from "./utils/typography.js";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { forwardRef } from "react";
|
|
7
|
+
import styled, { css } from "styled-components";
|
|
8
|
+
//#region src/lib/prose.tsx
|
|
9
|
+
var accent = (theme) => theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark;
|
|
10
|
+
/**
|
|
11
|
+
* Styles for rendered markdown: links, lists, tables, code, media and
|
|
12
|
+
* headings. Exported so it can be applied to an element that is already
|
|
13
|
+
* styled, rather than wrapping it in another <div>.
|
|
14
|
+
*/ var proseStyles = (theme, $compact) => {
|
|
15
|
+
const block = $compact ? "10px" : "20px";
|
|
16
|
+
return css([
|
|
17
|
+
`color:`,
|
|
18
|
+
`;`,
|
|
19
|
+
`;& > *:first-child{margin-top:0;}& > *:last-child{margin-bottom:0;& > *:last-child{margin-bottom:0;}}& p{margin:0 0 `,
|
|
20
|
+
`;`,
|
|
21
|
+
`;}& h1,& h2,& h3,& h4,& h5,& h6{margin:`,
|
|
22
|
+
` 0;padding:0;color:`,
|
|
23
|
+
`;}& h1{`,
|
|
24
|
+
`;}& h2{`,
|
|
25
|
+
`;}& h3{`,
|
|
26
|
+
`;}& h4{`,
|
|
27
|
+
`;}& h5{`,
|
|
28
|
+
`;}& h6{`,
|
|
29
|
+
`;}& a:not([class]):not(:has(img)){color:inherit;transition:all 0.3s ease;text-decoration:none;box-shadow:0 2px 0 0 `,
|
|
30
|
+
`;&:hover{color:`,
|
|
31
|
+
`;box-shadow:0 1px 0 0 `,
|
|
32
|
+
`;}&:focus-visible{outline:none;border-radius:`,
|
|
33
|
+
`;box-shadow:0 2px 0 0 `,
|
|
34
|
+
`,0 0 0 2px `,
|
|
35
|
+
`;}}& ul,& ol{margin:0 0 `,
|
|
36
|
+
`;padding:0;& li{& > .code-wrapper{margin:10px 0;}& p{display:inline;}}}& ul{list-style:none;& li{text-indent:0;display:block;position:relative;padding:0 0 0 24px;margin:0;`,
|
|
37
|
+
`;&::before{content:"";display:block;width:6px;height:6px;border-radius:50%;background:`,
|
|
38
|
+
`;position:absolute;top:0.65em;left:9px;}}}& ol{counter-reset:item;& > li{counter-increment:item;padding:0 0 0 24px;margin:0;`,
|
|
39
|
+
`;&::before{content:counter(item) ".";display:inline-block;min-width:20px;margin-left:-24px;margin-right:4px;text-align:right;font-weight:700;color:`,
|
|
40
|
+
`;}}}& code:not([class]){background:`,
|
|
41
|
+
`;color:`,
|
|
42
|
+
`;padding:2px 4px;border-radius:`,
|
|
43
|
+
`;font-family:`,
|
|
44
|
+
`;white-space:pre;}& pre,& .hljs{margin:10px 0;overflow-x:auto;`,
|
|
45
|
+
`;}& .code-wrapper pre{margin:0;}& blockquote{margin:`,
|
|
46
|
+
` 0;padding:0 0 0 16px;border-left:solid 2px `,
|
|
47
|
+
`;color:`,
|
|
48
|
+
`;}& hr{margin:`,
|
|
49
|
+
` 0;border:none;border-bottom:solid 1px `,
|
|
50
|
+
`;}& .table-wrapper{overflow-x:auto;width:100%;margin:0 0 `,
|
|
51
|
+
`;`,
|
|
52
|
+
`;}& table{margin:0;padding:0;border-collapse:collapse;width:100%;text-align:left;& tr{margin:0;padding:0;}& th{border-bottom:solid 1px `,
|
|
53
|
+
`;padding:10px 10px 10px 0;`,
|
|
54
|
+
`;font-weight:600;color:`,
|
|
55
|
+
`;}& td{border-bottom:solid 1px `,
|
|
56
|
+
`;padding:10px 10px 10px 0;color:`,
|
|
57
|
+
`;`,
|
|
58
|
+
`;}}& img,& video,& iframe{max-width:100%;border-radius:`,
|
|
59
|
+
`;margin:10px 0;display:block;}`
|
|
60
|
+
], theme.colors.dark, styledText(theme), block, styledText(theme), block, theme.colors.dark, ($compact ? styledH3 : styledH1)(theme), ($compact ? styledH4 : styledH2)(theme), ($compact ? styledH5 : styledH3)(theme), ($compact ? styledH6 : styledH4)(theme), ($compact ? styledH6 : styledH5)(theme), styledH6(theme), theme.colors.primary, accent(theme), theme.colors.primary, theme.spacing.radius.xs, theme.colors.primary, theme.colors.primaryLight, block, styledText(theme), theme.colors.primary, styledText(theme), theme.colors.primary, alpha(theme.colors.primaryLight, 20), theme.colors.dark, theme.spacing.radius.xs, theme.fonts.mono, thinScrollbar, block, theme.colors.grayLight, theme.colors.grayDark, block, theme.colors.grayLight, block, thinScrollbar, theme.colors.grayLight, styledSmall(theme), theme.colors.dark, theme.colors.grayLight, theme.colors.grayDark, styledSmall(theme), theme.spacing.radius.lg);
|
|
61
|
+
};
|
|
62
|
+
var StyledProse = styled.div.withConfig({
|
|
63
|
+
displayName: "prose__StyledProse",
|
|
64
|
+
componentId: "sc-91bd953a-0"
|
|
65
|
+
})([``, `;`], ({ theme, $compact }) => proseStyles(theme, $compact));
|
|
66
|
+
function LocalProse({ children, ...props }, ref) {
|
|
67
|
+
return /*#__PURE__*/ jsx(StyledProse, {
|
|
68
|
+
...props,
|
|
69
|
+
ref,
|
|
70
|
+
children
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
var Prose = /*#__PURE__*/ forwardRef(LocalProse);
|
|
74
|
+
//#endregion
|
|
75
|
+
export { Prose, proseStyles };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IconProps } from './icon';
|
|
2
|
+
export interface SpinnerProps {
|
|
3
|
+
/** Lucide icon to rotate. */
|
|
4
|
+
name?: IconProps;
|
|
5
|
+
color?: string;
|
|
6
|
+
size?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
"aria-label"?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const Spinner: ({ name, ...props }: SpinnerProps) => import("react").JSX.Element;
|
|
11
|
+
export { Spinner };
|
package/dist/spinner.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { Icon } from "./icon.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import styled, { keyframes } from "styled-components";
|
|
6
|
+
//#region src/lib/spinner.tsx
|
|
7
|
+
var spin = keyframes([`0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}`]);
|
|
8
|
+
var StyledSpinner = styled(Icon).withConfig({
|
|
9
|
+
displayName: "spinner__StyledSpinner",
|
|
10
|
+
componentId: "sc-bb636095-0"
|
|
11
|
+
})([
|
|
12
|
+
`color:`,
|
|
13
|
+
`;animation:`,
|
|
14
|
+
` 1s linear infinite;@media (prefers-reduced-motion:reduce){animation:none;}`
|
|
15
|
+
], ({ theme }) => theme.colors.dark, spin);
|
|
16
|
+
var Spinner = ({ name = "LoaderCircle", ...props }) => /*#__PURE__*/ jsx(StyledSpinner, {
|
|
17
|
+
name,
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
//#endregion
|
|
21
|
+
export { Spinner };
|
|
@@ -6,7 +6,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
import { useEffect, useMemo, useState } from "react";
|
|
7
7
|
import { ThemeProvider } from "styled-components";
|
|
8
8
|
//#region src/lib/styled-components/client-theme-provider.tsx
|
|
9
|
-
var THEME_COOKIE_MAX_AGE =
|
|
9
|
+
var THEME_COOKIE_MAX_AGE = 31536e3;
|
|
10
10
|
function readThemeCookie() {
|
|
11
11
|
const cookie = document.cookie.split(";").map((c) => c.trim()).find((c) => c.startsWith("theme="));
|
|
12
12
|
const value = cookie ? cookie.split("=")[1] : void 0;
|
|
@@ -22,6 +22,11 @@ function removeThemeInitStyle() {
|
|
|
22
22
|
const el = document.getElementById("__theme-init");
|
|
23
23
|
if (el) el.remove();
|
|
24
24
|
}
|
|
25
|
+
function resolveColor(value) {
|
|
26
|
+
const match = /^var\(\s*(--[^,)\s]+)\s*(?:,([^)]*))?\)$/.exec(value.trim());
|
|
27
|
+
if (!match) return value;
|
|
28
|
+
return getComputedStyle(document.documentElement).getPropertyValue(match[1]).trim() || match[2]?.trim() || value;
|
|
29
|
+
}
|
|
25
30
|
/**
|
|
26
31
|
* SSR-aware theme provider. Renders with the server-resolved theme on the
|
|
27
32
|
* first paint (no dark-mode flash), reconciles it against the `theme` cookie
|
|
@@ -32,9 +37,11 @@ function removeThemeInitStyle() {
|
|
|
32
37
|
*/ function ClientThemeProvider({ children, theme, themeDark, $initial = "light", $themeColor = "light", $globalStyles = true }) {
|
|
33
38
|
const initialTheme = $initial === "dark" && themeDark ? themeDark : theme;
|
|
34
39
|
const [overrideTheme, setOverrideTheme] = useState(null);
|
|
40
|
+
const [reconciled, setReconciled] = useState(false);
|
|
35
41
|
const effectiveTheme = useMemo(() => overrideTheme ?? initialTheme, [overrideTheme, initialTheme]);
|
|
36
42
|
useEffect(() => {
|
|
37
43
|
if (!themeDark) {
|
|
44
|
+
setReconciled(true);
|
|
38
45
|
removeThemeInitStyle();
|
|
39
46
|
return;
|
|
40
47
|
}
|
|
@@ -54,20 +61,23 @@ function removeThemeInitStyle() {
|
|
|
54
61
|
const wantDark = cookieValue === "dark";
|
|
55
62
|
if (initialTheme.isDark !== wantDark) {
|
|
56
63
|
setOverrideTheme(wantDark ? themeDark : theme);
|
|
64
|
+
setReconciled(true);
|
|
57
65
|
return;
|
|
58
66
|
}
|
|
59
67
|
} catch {}
|
|
68
|
+
setReconciled(true);
|
|
60
69
|
removeThemeInitStyle();
|
|
61
70
|
}, []);
|
|
62
71
|
useEffect(() => {
|
|
63
72
|
if (overrideTheme) removeThemeInitStyle();
|
|
64
73
|
}, [overrideTheme]);
|
|
65
74
|
useEffect(() => {
|
|
75
|
+
if (!reconciled) return;
|
|
66
76
|
document.documentElement.classList.toggle("dark", effectiveTheme.isDark);
|
|
67
|
-
}, [effectiveTheme.isDark]);
|
|
77
|
+
}, [effectiveTheme.isDark, reconciled]);
|
|
68
78
|
useEffect(() => {
|
|
69
79
|
if (!$themeColor) return;
|
|
70
|
-
const background = effectiveTheme.colors[$themeColor];
|
|
80
|
+
const background = resolveColor(effectiveTheme.colors[$themeColor]);
|
|
71
81
|
let meta = document.querySelector("meta[name=\"theme-color\"]");
|
|
72
82
|
if (!meta) {
|
|
73
83
|
meta = document.createElement("meta");
|
package/dist/tabs.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
|
-
import { resetButton } from "./utils/mixins.js";
|
|
3
|
+
import { alpha, resetButton } from "./utils/mixins.js";
|
|
4
4
|
import { styledText } from "./utils/typography.js";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import React, { useId, useRef, useState } from "react";
|
|
7
7
|
import styled, { css } from "styled-components";
|
|
8
|
-
import { rgba } from "polished";
|
|
9
8
|
//#region src/lib/tabs.tsx
|
|
10
9
|
var StyledTabs = styled.div.withConfig({
|
|
11
10
|
displayName: "tabs__StyledTabs",
|
|
12
|
-
componentId: "sc-
|
|
11
|
+
componentId: "sc-60ef8245-0"
|
|
13
12
|
})([`width:100%;`]);
|
|
14
13
|
var StyledTabsList = styled.div.withConfig({
|
|
15
14
|
displayName: "tabs__StyledTabsList",
|
|
16
|
-
componentId: "sc-
|
|
15
|
+
componentId: "sc-60ef8245-1"
|
|
17
16
|
})([
|
|
18
17
|
`display:flex;overflow-x:auto;border-radius:`,
|
|
19
18
|
` `,
|
|
@@ -23,7 +22,7 @@ var StyledTabsList = styled.div.withConfig({
|
|
|
23
22
|
], ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight);
|
|
24
23
|
var StyledTabButton = styled.button.withConfig({
|
|
25
24
|
displayName: "tabs__StyledTabButton",
|
|
26
|
-
componentId: "sc-
|
|
25
|
+
componentId: "sc-60ef8245-2"
|
|
27
26
|
})([
|
|
28
27
|
``,
|
|
29
28
|
`;flex:1;min-width:fit-content;padding:12px 20px;`,
|
|
@@ -41,10 +40,10 @@ var StyledTabButton = styled.button.withConfig({
|
|
|
41
40
|
`&:hover{color:`,
|
|
42
41
|
`;background:`,
|
|
43
42
|
`;}`
|
|
44
|
-
], theme.colors.primary,
|
|
43
|
+
], theme.colors.primary, alpha(theme.colors.primaryLight, 10)));
|
|
45
44
|
var StyledTabPanel = styled.div.withConfig({
|
|
46
45
|
displayName: "tabs__StyledTabPanel",
|
|
47
|
-
componentId: "sc-
|
|
46
|
+
componentId: "sc-60ef8245-3"
|
|
48
47
|
})([
|
|
49
48
|
``,
|
|
50
49
|
`;color:`,
|
package/dist/theme-toggle.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
|
-
import { interactiveStyles, resetButton } from "./utils/mixins.js";
|
|
3
|
+
import { alpha, interactiveStyles, resetButton } from "./utils/mixins.js";
|
|
4
4
|
import { ThemeContext } from "./styled-components/theme-provider.js";
|
|
5
5
|
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 { rgba } from "polished";
|
|
10
9
|
//#region src/lib/theme-toggle.tsx
|
|
11
10
|
var StyledThemeToggle = styled.button.withConfig({
|
|
12
11
|
displayName: "theme-toggle__StyledThemeToggle",
|
|
13
|
-
componentId: "sc-
|
|
12
|
+
componentId: "sc-f8700a2a-0"
|
|
14
13
|
})([
|
|
15
14
|
``,
|
|
16
15
|
` `,
|
|
@@ -18,11 +17,12 @@ var StyledThemeToggle = styled.button.withConfig({
|
|
|
18
17
|
`;border-color:`,
|
|
19
18
|
`;&::after{content:"";position:absolute;top:2px;left:2px;width:24px;height:24px;border-radius:50%;background:`,
|
|
20
19
|
`;transition:all 0.3s ease;z-index:1;`,
|
|
21
|
-
`}`,
|
|
20
|
+
`}:root.dark &::after{transform:translateX(26px);}`,
|
|
22
21
|
` & svg{width:16px;height:16px;object-fit:contain;transition:all 0.3s ease;position:relative;z-index:2;}& svg[stroke]{stroke:`,
|
|
23
22
|
`;}&:hover svg[stroke]{stroke:`,
|
|
23
|
+
`;}:root.dark &:hover svg[stroke]{stroke:`,
|
|
24
24
|
`;}`
|
|
25
|
-
], resetButton, interactiveStyles, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) =>
|
|
25
|
+
], resetButton, interactiveStyles, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) => alpha(theme.colors.primaryLight, 20), ({ theme }) => theme.isDark && css([`transform:translateX(26px);`]), ({ $hidden }) => $hidden && css([`display:none;`]), ({ theme }) => theme.colors.primary, ({ theme }) => theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark, ({ theme }) => theme.colors.primaryLight);
|
|
26
26
|
function LocalThemeToggle({ onClick, $shortcut = false, ...props }, ref) {
|
|
27
27
|
const { toggleTheme } = useContext(ThemeContext);
|
|
28
28
|
useEffect(() => {
|
package/dist/toast.d.ts
CHANGED
|
@@ -35,14 +35,14 @@ export declare const StyledNotifications: import('styled-components/dist/types')
|
|
|
35
35
|
$align?: ToastAlign;
|
|
36
36
|
$bottom?: boolean;
|
|
37
37
|
}, never>>> & string;
|
|
38
|
-
export declare const StyledNotificationItem: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('styled-components').FastOmit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "theme" | "$
|
|
38
|
+
export declare const StyledNotificationItem: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('styled-components').FastOmit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "theme" | "$color" | "$align" | "$bottom" | "$visible" | "$static"> & {
|
|
39
39
|
theme: Theme;
|
|
40
40
|
$color: ToastColor;
|
|
41
41
|
$visible: boolean;
|
|
42
42
|
$static: boolean;
|
|
43
43
|
$align?: ToastAlign;
|
|
44
44
|
$bottom?: boolean;
|
|
45
|
-
}, never> & Partial<Pick<import('styled-components').FastOmit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "theme" | "$
|
|
45
|
+
}, never> & Partial<Pick<import('styled-components').FastOmit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "theme" | "$color" | "$align" | "$bottom" | "$visible" | "$static"> & {
|
|
46
46
|
theme: Theme;
|
|
47
47
|
$color: ToastColor;
|
|
48
48
|
$visible: boolean;
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/mixins.d.ts
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
1
|
import { Breakpoints, Theme } from './theme';
|
|
2
|
+
/**
|
|
3
|
+
* Fades a color toward transparent. Native CSS rather than a JS color library
|
|
4
|
+
* so the input can be any valid CSS color value, including a `var(--token)`
|
|
5
|
+
* reference that only the browser can resolve.
|
|
6
|
+
*/
|
|
7
|
+
export declare const alpha: (color: string, percent: number) => string;
|
|
8
|
+
/** Darkens a color by mixing it toward black. See `alpha` for why it is CSS. */
|
|
9
|
+
export declare const shade: (color: string, percent: number) => string;
|
|
10
|
+
/** Lightens a color by mixing it toward white. See `alpha` for why it is CSS. */
|
|
11
|
+
export declare const tint: (color: string, percent: number) => string;
|
|
12
|
+
/**
|
|
13
|
+
* Text color for a label sitting on a brand-colored fill: the palette's
|
|
14
|
+
* contrasting end, `light` in light mode and `dark` in dark mode.
|
|
15
|
+
*/
|
|
16
|
+
export declare const filledTextColor: (theme: Theme) => string;
|
|
17
|
+
/**
|
|
18
|
+
* The same choice restated as a rule scoped to a `dark` class on <html>, which
|
|
19
|
+
* is what apps resolving the mode in CSS key off before hydration can swap the
|
|
20
|
+
* theme object. Additive: with an already-dark theme object both paths resolve
|
|
21
|
+
* to the same color. Interpolate alongside `filledTextColor`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const darkFilledTextRule: (theme: Theme) => string;
|
|
24
|
+
/**
|
|
25
|
+
* Slim, theme-aware scrollbar for internal scroll areas (chat transcripts, code
|
|
26
|
+
* blocks, tables) so the chunky native bar doesn't stand out, especially in
|
|
27
|
+
* dark mode.
|
|
28
|
+
*/
|
|
29
|
+
export declare const thinScrollbar: import('styled-components').RuleSet<NoInfer<{
|
|
30
|
+
theme: Theme;
|
|
31
|
+
}>>;
|
|
2
32
|
/**
|
|
3
33
|
* Hover/focus/active affordance for interactive surfaces (cards, tiles,
|
|
4
34
|
* links-as-blocks): a transparent 1px border that picks up the primary color
|
package/dist/utils/mixins.js
CHANGED
|
@@ -2,9 +2,30 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { mq } from "./theme.js";
|
|
4
4
|
import { css } from "styled-components";
|
|
5
|
-
import { rgba } from "polished";
|
|
6
5
|
//#region src/lib/utils/mixins.tsx
|
|
7
6
|
/**
|
|
7
|
+
* Fades a color toward transparent. Native CSS rather than a JS color library
|
|
8
|
+
* so the input can be any valid CSS color value, including a `var(--token)`
|
|
9
|
+
* reference that only the browser can resolve.
|
|
10
|
+
*/ var alpha = (color, percent) => `color-mix(in srgb, ${color} ${percent}%, transparent)`;
|
|
11
|
+
/** Darkens a color by mixing it toward black. See `alpha` for why it is CSS. */ var shade = (color, percent) => `color-mix(in srgb, ${color} ${100 - percent}%, black)`;
|
|
12
|
+
/** Lightens a color by mixing it toward white. See `alpha` for why it is CSS. */ var tint = (color, percent) => `color-mix(in srgb, ${color} ${100 - percent}%, white)`;
|
|
13
|
+
/**
|
|
14
|
+
* Text color for a label sitting on a brand-colored fill: the palette's
|
|
15
|
+
* contrasting end, `light` in light mode and `dark` in dark mode.
|
|
16
|
+
*/ var filledTextColor = (theme) => theme.isDark ? theme.colors.dark : theme.colors.light;
|
|
17
|
+
/**
|
|
18
|
+
* The same choice restated as a rule scoped to a `dark` class on <html>, which
|
|
19
|
+
* is what apps resolving the mode in CSS key off before hydration can swap the
|
|
20
|
+
* theme object. Additive: with an already-dark theme object both paths resolve
|
|
21
|
+
* to the same color. Interpolate alongside `filledTextColor`.
|
|
22
|
+
*/ var darkFilledTextRule = (theme) => `:root.dark & { color: ${theme.colors.dark}; }`;
|
|
23
|
+
/**
|
|
24
|
+
* Slim, theme-aware scrollbar for internal scroll areas (chat transcripts, code
|
|
25
|
+
* blocks, tables) so the chunky native bar doesn't stand out, especially in
|
|
26
|
+
* dark mode.
|
|
27
|
+
*/ var thinScrollbar = css([`scrollbar-width:thin;scrollbar-color:`, ` transparent;`], ({ theme }) => theme.colors.grayLight);
|
|
28
|
+
/**
|
|
8
29
|
* Hover/focus/active affordance for interactive surfaces (cards, tiles,
|
|
9
30
|
* links-as-blocks): a transparent 1px border that picks up the primary color
|
|
10
31
|
* on hover, with a soft focus ring. Pair with resetButton for clickable
|
|
@@ -28,7 +49,7 @@ import { rgba } from "polished";
|
|
|
28
49
|
`;box-shadow:0 0 0 4px `,
|
|
29
50
|
`;}&:active{box-shadow:0 0 0 2px `,
|
|
30
51
|
`;}`
|
|
31
|
-
], ({ theme }) => theme.colors.error, ({ theme }) => theme.colors.error, ({ theme }) => theme.colors.error, ({ theme }) =>
|
|
52
|
+
], ({ theme }) => theme.colors.error, ({ theme }) => theme.colors.error, ({ theme }) => theme.colors.error, ({ theme }) => alpha(theme.colors.error, 30), ({ theme }) => alpha(theme.colors.error, 30));
|
|
32
53
|
var resetButton = css([`box-sizing:border-box;appearance:none;border:none;background:none;padding:0;margin:0;cursor:pointer;outline:none;`]);
|
|
33
54
|
var resetInput = css([`cursor:text;min-width:100px;`]);
|
|
34
55
|
var fullWidthStyles = (fullWidth) => {
|
|
@@ -84,4 +105,4 @@ var generateDirectionStyles = (size, direction) => css([
|
|
|
84
105
|
`;}`
|
|
85
106
|
], mq(size), direction && `${direction}`);
|
|
86
107
|
//#endregion
|
|
87
|
-
export { errorInteractiveStyles, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, interactiveStyles, resetButton, resetInput, statusBorderStyles };
|
|
108
|
+
export { alpha, darkFilledTextRule, errorInteractiveStyles, filledTextColor, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, interactiveStyles, resetButton, resetInput, shade, statusBorderStyles, thinScrollbar, tint };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
//#region src/lib/utils/use-lock-body-scroll.tsx
|
|
5
|
+
var lockCount = 0;
|
|
6
|
+
var previousOverflow = "";
|
|
7
|
+
/**
|
|
8
|
+
* Freezes body scrolling while `isLocked` is true. Safe to nest: the body is
|
|
9
|
+
* restored only when every active lock has been released.
|
|
10
|
+
*/ function useLockBodyScroll(isLocked) {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!isLocked) return;
|
|
13
|
+
if (lockCount === 0) {
|
|
14
|
+
previousOverflow = document.body.style.overflow;
|
|
15
|
+
document.body.style.overflow = "hidden";
|
|
16
|
+
}
|
|
17
|
+
lockCount += 1;
|
|
18
|
+
return () => {
|
|
19
|
+
lockCount -= 1;
|
|
20
|
+
if (lockCount === 0) document.body.style.overflow = previousOverflow;
|
|
21
|
+
};
|
|
22
|
+
}, [isLocked]);
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { useLockBodyScroll };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Breakpoints } from './theme';
|
|
2
|
+
/**
|
|
3
|
+
* Subscribes to a media query. Returns `false` on the server and during the
|
|
4
|
+
* first client render so hydration matches, then re-renders with the real
|
|
5
|
+
* match. Pass a full media query string, e.g. "(max-width: 991px)".
|
|
6
|
+
*/
|
|
7
|
+
export declare function useMediaQuery(query: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* True while the viewport is narrower than the named breakpoint, i.e. the
|
|
10
|
+
* inverse of the `mq()` helper's min-width query. Handy for behavior (not
|
|
11
|
+
* styling) that has to change below a breakpoint, such as a side panel turning
|
|
12
|
+
* into a full-screen modal.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useBelowBreakpoint(size: keyof Breakpoints): boolean;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { breakpoints } from "./theme.js";
|
|
4
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
5
|
+
//#region src/lib/utils/use-media-query.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Subscribes to a media query. Returns `false` on the server and during the
|
|
8
|
+
* first client render so hydration matches, then re-renders with the real
|
|
9
|
+
* match. Pass a full media query string, e.g. "(max-width: 991px)".
|
|
10
|
+
*/ function useMediaQuery(query) {
|
|
11
|
+
const subscribe = useCallback((onChange) => {
|
|
12
|
+
const mediaQuery = window.matchMedia(query);
|
|
13
|
+
mediaQuery.addEventListener("change", onChange);
|
|
14
|
+
return () => mediaQuery.removeEventListener("change", onChange);
|
|
15
|
+
}, [query]);
|
|
16
|
+
const getSnapshot = useCallback(() => window.matchMedia(query).matches, [query]);
|
|
17
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => false);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* True while the viewport is narrower than the named breakpoint, i.e. the
|
|
21
|
+
* inverse of the `mq()` helper's min-width query. Handy for behavior (not
|
|
22
|
+
* styling) that has to change below a breakpoint, such as a side panel turning
|
|
23
|
+
* into a full-screen modal.
|
|
24
|
+
*/ function useBelowBreakpoint(size) {
|
|
25
|
+
return useMediaQuery(`(max-width: ${breakpoints[size] - 1}px)`);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { useBelowBreakpoint, useMediaQuery };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cherry-styled-components",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
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",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"homepage": "https://cherry.al",
|
|
21
21
|
"repository": "https://github.com/cherry-design-system/styled-components",
|
|
22
22
|
"license": "MIT",
|
|
23
|
+
"packageManager": "pnpm@11.19.0",
|
|
23
24
|
"engines": {
|
|
24
25
|
"node": ">=18.0.0"
|
|
25
26
|
},
|
|
@@ -40,11 +41,11 @@
|
|
|
40
41
|
"build": "vite build",
|
|
41
42
|
"build:demo": "vite build --mode demo",
|
|
42
43
|
"format": "prettier --write .",
|
|
44
|
+
"format:check": "prettier --check .",
|
|
43
45
|
"screenshots": "node scripts/screenshot-previews.cjs"
|
|
44
46
|
},
|
|
45
47
|
"dependencies": {
|
|
46
|
-
"lucide-react": "^1.
|
|
47
|
-
"polished": "^4.3.1"
|
|
48
|
+
"lucide-react": "^1.28.0"
|
|
48
49
|
},
|
|
49
50
|
"peerDependencies": {
|
|
50
51
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -53,23 +54,23 @@
|
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@swc/plugin-styled-components": "^12.15.0",
|
|
56
|
-
"@types/node": "^26.1.
|
|
57
|
-
"@types/react": "^19.2.
|
|
58
|
-
"@types/react-dom": "^19.2.
|
|
57
|
+
"@types/node": "^26.1.2",
|
|
58
|
+
"@types/react": "^19.2.18",
|
|
59
|
+
"@types/react-dom": "^19.2.4",
|
|
59
60
|
"@typescript/typescript6": "^6.0.2",
|
|
60
|
-
"@vitejs/plugin-react-swc": "^4.3.
|
|
61
|
+
"@vitejs/plugin-react-swc": "^4.3.3",
|
|
61
62
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
62
63
|
"eslint-plugin-react-refresh": "^0.5.3",
|
|
63
|
-
"next": "^16.2.
|
|
64
|
-
"playwright-core": "^1.
|
|
65
|
-
"prettier": "^3.9.
|
|
66
|
-
"react": "^19.2.
|
|
67
|
-
"react-dom": "^19.2.
|
|
64
|
+
"next": "^16.2.12",
|
|
65
|
+
"playwright-core": "^1.62.1",
|
|
66
|
+
"prettier": "^3.9.6",
|
|
67
|
+
"react": "^19.2.8",
|
|
68
|
+
"react-dom": "^19.2.8",
|
|
68
69
|
"rollup-plugin-preserve-directives": "^0.4.0",
|
|
69
70
|
"sharp": "^0.35.3",
|
|
70
|
-
"styled-components": "^6.4.
|
|
71
|
+
"styled-components": "^6.4.4",
|
|
71
72
|
"typescript": "^7.0.2",
|
|
72
|
-
"vite": "^8.
|
|
73
|
+
"vite": "^8.2.0",
|
|
73
74
|
"vite-plugin-dts": "^5.0.3"
|
|
74
75
|
}
|
|
75
76
|
}
|