cherry-styled-components 0.2.2 → 0.2.4

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.
@@ -5,7 +5,8 @@ export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonEl
5
5
  "aria-label": string;
6
6
  $size?: "default" | "big" | "small";
7
7
  $error?: boolean;
8
+ $active?: boolean;
8
9
  }
9
- export declare const iconButtonStyles: (theme: Theme, $size?: "default" | "big" | "small", $error?: boolean, disabled?: boolean) => import('styled-components').RuleSet<object>;
10
+ export declare const iconButtonStyles: (theme: Theme, $size?: "default" | "big" | "small", $error?: boolean, disabled?: boolean, $active?: boolean) => import('styled-components').RuleSet<object>;
10
11
  declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
12
  export { IconButton };
@@ -4,7 +4,7 @@ import { resetButton } from "./utils/mixins.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { forwardRef } from "react";
6
6
  import styled, { css } from "styled-components";
7
- import { darken, lighten } from "polished";
7
+ import { darken, lighten, rgba } from "polished";
8
8
  //#region src/lib/icon-button.tsx
9
9
  var iconButtonSizes = {
10
10
  small: {
@@ -20,11 +20,11 @@ var iconButtonSizes = {
20
20
  icon: 16
21
21
  }
22
22
  };
23
- var iconButtonStyles = (theme, $size, $error, disabled) => {
23
+ var iconButtonStyles = (theme, $size, $error, disabled, $active) => {
24
24
  const { box, icon } = iconButtonSizes[$size ?? "default"];
25
25
  return css([
26
26
  ``,
27
- `;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:`,
27
+ `;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;width:`,
28
28
  `px;height:`,
29
29
  `px;border-radius:50%;background:`,
30
30
  `;border:solid 2px `,
@@ -34,6 +34,7 @@ var iconButtonStyles = (theme, $size, $error, disabled) => {
34
34
  `px;height:`,
35
35
  `px;}`,
36
36
  ` `,
37
+ ` `,
37
38
  ``
38
39
  ], resetButton, box, box, theme.colors.light, theme.colors.grayLight, $error ? theme.colors.error : theme.colors.grayDark, $error ? lighten(.1, theme.colors.error) : theme.colors.primaryLight, icon, icon, !disabled && ($error ? css([
39
40
  `border-color:`,
@@ -49,7 +50,12 @@ var iconButtonStyles = (theme, $size, $error, disabled) => {
49
50
  `;border-color:`,
50
51
  `;}&:active{box-shadow:0 0 0 2px `,
51
52
  `;}`
52
- ], theme.colors.primary, theme.colors.primary, theme.colors.primaryLight, theme.colors.primary, theme.colors.primaryLight)), disabled && css([
53
+ ], theme.colors.primary, theme.colors.primary, theme.colors.primaryLight, theme.colors.primary, theme.colors.primaryLight)), !disabled && $active && css([
54
+ `border-color:`,
55
+ `;background:`,
56
+ `;color:`,
57
+ `;`
58
+ ], theme.colors.primary, rgba(theme.colors.primary, theme.isDark ? .18 : .1), theme.colors.primary), disabled && css([
53
59
  `cursor:not-allowed;background:`,
54
60
  `;border-color:`,
55
61
  `;color:`,
@@ -58,11 +64,12 @@ var iconButtonStyles = (theme, $size, $error, disabled) => {
58
64
  };
59
65
  var StyledIconButton = styled.button.withConfig({
60
66
  displayName: "icon-button__StyledIconButton",
61
- componentId: "sc-def35ae6-0"
62
- })([``, ``], ({ theme, $size, $error, disabled }) => iconButtonStyles(theme, $size, $error, disabled));
67
+ componentId: "sc-e26e58e2-0"
68
+ })([``, ``], ({ theme, $size, $error, disabled, $active }) => iconButtonStyles(theme, $size, $error, disabled, $active));
63
69
  function LocalIconButton({ ...props }, ref) {
64
70
  return /*#__PURE__*/ jsx(StyledIconButton, {
65
71
  type: "button",
72
+ "aria-pressed": props.$active === void 0 ? void 0 : props.$active,
66
73
  ...props,
67
74
  ref
68
75
  });
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ export * from './password';
18
18
  export * from './range';
19
19
  export * from './select';
20
20
  export * from './space';
21
+ export * from './tabs';
21
22
  export * from './textarea';
22
23
  export * from './theme-toggle';
23
24
  export * from './toast';
package/dist/index.js CHANGED
@@ -26,8 +26,9 @@ import { Password } from "./password.js";
26
26
  import { Range } from "./range.js";
27
27
  import { Select, StyledIconWrapper } from "./select.js";
28
28
  import { Space } from "./space.js";
29
+ import { TabContent, Tabs } from "./tabs.js";
29
30
  import { Textarea } from "./textarea.js";
30
31
  import { ThemeToggle } from "./theme-toggle.js";
31
32
  import { StyledNotificationItem, StyledNotifications, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, useToastNotifications } from "./toast.js";
32
33
  import { Toggle } from "./toggle.js";
33
- export { Accordion, AvatarDropzone, Box, Button, CherryThemeProvider, ClientThemeProvider, Col, Container, Dropzone, Flex, GlobalStyles, Grid, Icon, IconArrow, IconButton, IconCalendar, IconCheck, Input, MaxWidth, Modal, Password, Range, Select, Space, StyledComponentsRegistry, StyledIconWrapper, StyledInputWrapper, StyledLabel, StyledNotificationItem, StyledNotifications, Textarea, ThemeContext, ThemeToggle, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, Toggle, breakpoints, buttonStyles, colors, colorsDark, createThemeInitScript, createTypographyStyle, errorInteractiveStyles, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, iconButtonStyles, interactiveStyles, lineHeights, matchesAccept, mq, resetButton, resetInput, resolveTheme, shadows, shadowsDark, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark, themeInitScript, useOnClickOutside, useToastNotifications };
34
+ export { Accordion, AvatarDropzone, Box, Button, CherryThemeProvider, ClientThemeProvider, Col, Container, Dropzone, Flex, GlobalStyles, Grid, Icon, IconArrow, IconButton, IconCalendar, IconCheck, Input, MaxWidth, Modal, Password, Range, Select, Space, StyledComponentsRegistry, StyledIconWrapper, StyledInputWrapper, StyledLabel, StyledNotificationItem, StyledNotifications, TabContent, Tabs, Textarea, ThemeContext, ThemeToggle, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, Toggle, breakpoints, buttonStyles, colors, colorsDark, createThemeInitScript, createTypographyStyle, errorInteractiveStyles, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, iconButtonStyles, interactiveStyles, lineHeights, matchesAccept, mq, resetButton, resetInput, resolveTheme, shadows, shadowsDark, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark, themeInitScript, useOnClickOutside, useToastNotifications };
package/dist/modal.d.ts CHANGED
@@ -6,10 +6,14 @@ export interface ModalProps {
6
6
  $title?: string;
7
7
  $width?: number;
8
8
  $hideCloseButton?: boolean;
9
- /** Enables restyling via styled(Modal); applied to the overlay root. The
10
- inner parts expose class hooks: .modal-inner, .modal-close, .modal-title,
11
- .modal-content. */
9
+ /** Escape hatches for app-level restyling, both applied to the overlay
10
+ root. Note that wrapping with styled(Modal) does NOT work for the $-props
11
+ API (styled-components strips transient props before they reach the
12
+ wrapped component), so restyle by targeting a passed class instead. The
13
+ inner parts expose stable class hooks: .modal-inner, .modal-close,
14
+ .modal-title, .modal-content. */
12
15
  className?: string;
16
+ style?: React.CSSProperties;
13
17
  }
14
- declare function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className, }: ModalProps): React.ReactPortal | null;
18
+ declare function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className, style, }: ModalProps): React.ReactPortal | null;
15
19
  export { Modal };
package/dist/modal.js CHANGED
@@ -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-e8a3a913-0"
24
+ componentId: "sc-14a8d5c-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:`,
@@ -35,11 +35,11 @@ var StyledModal = styled.div.withConfig({
35
35
  ], ({ theme }) => rgba(theme.colors.primary, .5), ({ $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-e8a3a913-1"
38
+ componentId: "sc-14a8d5c-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-e8a3a913-2"
42
+ componentId: "sc-14a8d5c-2"
43
43
  })([
44
44
  `--divider-color:`,
45
45
  `;margin:0 0 15px 0;padding:0 0 15px 0;color:`,
@@ -48,13 +48,13 @@ 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-e8a3a913-3"
51
+ componentId: "sc-14a8d5c-3"
52
52
  })([
53
53
  `max-height:calc(100svh - 200px);overflow-y:auto;padding:5px;margin:-5px;--divider-color:`,
54
54
  `;`,
55
55
  `;& hr{margin:20px 0;border:none;border-bottom:solid 1px var(--divider-color);}`
56
56
  ], ({ theme }) => theme.colors.grayLight, ({ theme }) => styledText(theme));
57
- function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className }) {
57
+ function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton, className, style }) {
58
58
  const wrapperRef = useRef(null);
59
59
  const elmRef = useRef(null);
60
60
  const isClient = useIsClient();
@@ -85,6 +85,7 @@ function Modal({ children, $isOpen, $onClose, $title, $width, $hideCloseButton,
85
85
  $isClosing: isClosing,
86
86
  $width,
87
87
  className,
88
+ style,
88
89
  onAnimationEnd: handleAnimationEnd,
89
90
  children: /*#__PURE__*/ jsxs("div", {
90
91
  className: "modal-inner",
package/dist/tabs.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { default as React } from 'react';
2
+ export interface TabContentProps {
3
+ title: string;
4
+ children: React.ReactNode;
5
+ }
6
+ declare function TabContent({ children }: TabContentProps): React.JSX.Element;
7
+ export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
8
+ children: React.ReactNode;
9
+ onTabChange?: (index: number) => void;
10
+ defaultActiveTab?: number;
11
+ activeTab?: number;
12
+ }
13
+ declare function Tabs({ children, onTabChange, defaultActiveTab, activeTab, ...rest }: TabsProps): React.JSX.Element;
14
+ export { Tabs, TabContent };
package/dist/tabs.js ADDED
@@ -0,0 +1,120 @@
1
+ "use client";
2
+ "use client";
3
+ import { resetButton } from "./utils/mixins.js";
4
+ import { styledText } from "./utils/typography.js";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import React, { useId, useRef, useState } from "react";
7
+ import styled, { css } from "styled-components";
8
+ import { rgba } from "polished";
9
+ //#region src/lib/tabs.tsx
10
+ var StyledTabs = styled.div.withConfig({
11
+ displayName: "tabs__StyledTabs",
12
+ componentId: "sc-7af80746-0"
13
+ })([`width:100%;`]);
14
+ var StyledTabsList = styled.div.withConfig({
15
+ displayName: "tabs__StyledTabsList",
16
+ componentId: "sc-7af80746-1"
17
+ })([
18
+ `display:flex;overflow-x:auto;border-radius:`,
19
+ ` `,
20
+ ` 0 0;background:`,
21
+ `;border:solid 1px `,
22
+ `;`
23
+ ], ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight);
24
+ var StyledTabButton = styled.button.withConfig({
25
+ displayName: "tabs__StyledTabButton",
26
+ componentId: "sc-7af80746-2"
27
+ })([
28
+ ``,
29
+ `;flex:1;min-width:fit-content;padding:12px 20px;`,
30
+ `;font-weight:600;color:`,
31
+ `;border-bottom:solid 3px transparent;transition:color 0.2s ease,background 0.2s ease,border-color 0.2s ease;@media (prefers-reduced-motion:reduce){transition:none;}&:not(:last-child){border-right:solid 1px `,
32
+ `;}&:focus-visible{border-radius:`,
33
+ `;outline:solid 2px `,
34
+ `;outline-offset:-4px;border-bottom-color:transparent;}`,
35
+ ``
36
+ ], resetButton, ({ theme }) => styledText(theme), ({ theme }) => theme.colors.dark, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.spacing.radius.xs, ({ theme }) => theme.colors.primary, ({ theme, $isActive }) => $isActive ? css([
37
+ `color:`,
38
+ `;border-bottom-color:`,
39
+ `;`
40
+ ], theme.colors.primary, theme.colors.primary) : css([
41
+ `@media (hover:hover){&:hover{color:`,
42
+ `;background:`,
43
+ `;}}`
44
+ ], theme.colors.primary, rgba(theme.colors.primaryLight, .1)));
45
+ var StyledTabPanel = styled.div.withConfig({
46
+ displayName: "tabs__StyledTabPanel",
47
+ componentId: "sc-7af80746-3"
48
+ })([
49
+ ``,
50
+ `;color:`,
51
+ `;background:`,
52
+ `;padding:20px;border:solid 1px `,
53
+ `;border-top:none;border-radius:0 0 `,
54
+ ` `,
55
+ `;`
56
+ ], ({ theme }) => styledText(theme), ({ theme }) => theme.colors.grayDark, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.spacing.radius.lg);
57
+ function TabContent({ children }) {
58
+ return /*#__PURE__*/ jsx(Fragment, { children });
59
+ }
60
+ function Tabs({ children, onTabChange, defaultActiveTab, activeTab, ...rest }) {
61
+ const [internalActive, setInternalActive] = useState(defaultActiveTab ?? 0);
62
+ const isControlled = activeTab !== void 0;
63
+ const baseId = useId();
64
+ const tabRefs = useRef([]);
65
+ const tabs = React.Children.toArray(children).filter((child) => /*#__PURE__*/ React.isValidElement(child) && typeof child.props.title === "string" && child.props.title.trim() !== "");
66
+ const active = Math.min(isControlled ? activeTab : internalActive, Math.max(tabs.length - 1, 0));
67
+ const selectTab = (index) => {
68
+ if (!isControlled) setInternalActive(index);
69
+ onTabChange?.(index);
70
+ };
71
+ const handleKeyDown = (event) => {
72
+ let next;
73
+ switch (event.key) {
74
+ case "ArrowRight":
75
+ next = (active + 1) % tabs.length;
76
+ break;
77
+ case "ArrowLeft":
78
+ next = (active - 1 + tabs.length) % tabs.length;
79
+ break;
80
+ case "Home":
81
+ next = 0;
82
+ break;
83
+ case "End":
84
+ next = tabs.length - 1;
85
+ break;
86
+ default: return;
87
+ }
88
+ event.preventDefault();
89
+ selectTab(next);
90
+ tabRefs.current[next]?.focus();
91
+ };
92
+ return /*#__PURE__*/ jsxs(StyledTabs, {
93
+ ...rest,
94
+ children: [/*#__PURE__*/ jsx(StyledTabsList, {
95
+ role: "tablist",
96
+ onKeyDown: handleKeyDown,
97
+ children: tabs.map((tab, index) => /*#__PURE__*/ jsx(StyledTabButton, {
98
+ type: "button",
99
+ role: "tab",
100
+ id: `${baseId}-tab-${index}`,
101
+ "aria-selected": index === active,
102
+ "aria-controls": `${baseId}-panel-${index}`,
103
+ tabIndex: index === active ? 0 : -1,
104
+ $isActive: index === active,
105
+ ref: (node) => {
106
+ tabRefs.current[index] = node;
107
+ },
108
+ onClick: () => selectTab(index),
109
+ children: tab.props.title
110
+ }, index))
111
+ }), /*#__PURE__*/ jsx(StyledTabPanel, {
112
+ role: "tabpanel",
113
+ id: `${baseId}-panel-${active}`,
114
+ "aria-labelledby": `${baseId}-tab-${active}`,
115
+ children: tabs[active]?.props.children
116
+ })]
117
+ });
118
+ }
119
+ //#endregion
120
+ export { TabContent, Tabs };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  "use client";
3
- import { resetButton } from "./utils/mixins.js";
3
+ import { 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";
@@ -10,19 +10,19 @@ import { rgba } from "polished";
10
10
  //#region src/lib/theme-toggle.tsx
11
11
  var StyledThemeToggle = styled.button.withConfig({
12
12
  displayName: "theme-toggle__StyledThemeToggle",
13
- componentId: "sc-cc0c1ca5-0"
13
+ componentId: "sc-fe6f1d3-0"
14
14
  })([
15
15
  ``,
16
- ` width:56px;height:30px;border-radius:30px;display:flex;position:relative;margin:auto 0;transform:scale(1);background:`,
17
- `;border:1px solid `,
18
- `;transition:all 0.3s ease;&::after{content:"";position:absolute;top:2px;left:2px;width:24px;height:24px;border-radius:50%;background:`,
16
+ ` `,
17
+ ` width:56px;height:30px;border-radius:30px;display:flex;align-items:center;justify-content:space-between;padding:0 6px;position:relative;margin:auto 0;background:`,
18
+ `;border-color:`,
19
+ `;&::after{content:"";position:absolute;top:2px;left:2px;width:24px;height:24px;border-radius:50%;background:`,
19
20
  `;transition:all 0.3s ease;z-index:1;`,
20
21
  `}`,
21
- ` & svg{width:16px;height:16px;object-fit:contain;margin:auto;transition:all 0.3s ease;position:relative;z-index:2;}& .lucide-sun{transform:translateX(1px);}& svg[stroke]{stroke:`,
22
- `;}&:hover{transform:scale(1.05);color:`,
23
- `;& svg[stroke]{stroke:`,
24
- `;}}&:active{transform:scale(0.97);}`
25
- ], resetButton, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) => rgba(theme.colors.primaryLight, .2), ({ 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.isDark ? theme.colors.primaryLight : theme.colors.primaryDark);
22
+ ` & svg{width:16px;height:16px;object-fit:contain;transition:all 0.3s ease;position:relative;z-index:2;}& svg[stroke]{stroke:`,
23
+ `;}@media (hover:hover){&:hover svg[stroke]{stroke:`,
24
+ `;}}`
25
+ ], resetButton, interactiveStyles, ({ theme }) => theme.colors.light, ({ theme }) => theme.colors.grayLight, ({ theme }) => rgba(theme.colors.primaryLight, .2), ({ 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);
26
26
  function LocalThemeToggle({ onClick, ...props }, ref) {
27
27
  const { toggleTheme } = useContext(ThemeContext);
28
28
  return /*#__PURE__*/ jsxs(StyledThemeToggle, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cherry-styled-components",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
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",