@grantbii/design-system 2.0.0 → 3.0.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.
@@ -44,17 +44,14 @@ const BaseBadge = styled.div `
44
44
  display: flex;
45
45
  align-items: center;
46
46
  justify-content: space-between;
47
- gap: 10px;
47
+ gap: ${Spacing.px12};
48
48
 
49
49
  height: 26px;
50
50
  padding: 5px ${Spacing.px12};
51
- border-radius: 100px;
52
-
53
- font-size: 12px;
54
- font-weight: ${Typography.weight.medium};
55
51
 
56
52
  color: ${(props) => props.$color};
57
53
  background-color: ${(props) => props.$defaultBackgroundColor};
54
+ border-radius: ${Spacing.px100};
58
55
 
59
56
  cursor: ${(props) => (props.$isClickable ? "pointer" : "auto")};
60
57
 
@@ -67,10 +64,10 @@ const BaseBadge = styled.div `
67
64
  const BadgeContent = styled.div `
68
65
  display: flex;
69
66
  align-items: center;
70
- gap: 10px;
67
+ gap: ${Spacing.px4};
71
68
 
72
69
  width: ${({ $widthPixels }) => ($widthPixels ? `${$widthPixels}px` : "auto")};
73
- max-width: ${({ $hasX: $closeable }) => $closeable ? "calc(100% - 20px)" : "auto"};
70
+ max-width: ${({ $hasX: $closeable }) => $closeable ? `calc(100% - ${Spacing.px20})` : "auto"};
74
71
  `;
75
72
  const IconContainer = styled.div `
76
73
  display: flex;
@@ -85,13 +82,13 @@ const BadgeLabel = styled.div `
85
82
  white-space: nowrap;
86
83
  text-overflow: ellipsis;
87
84
 
88
- ${applyTypography(Typography.bodySecondaryMedium)}
85
+ ${applyTypography(Typography.captionMedium)}
89
86
  `;
90
87
  const XButton = ({ onClick }) => (_jsx(BaseCloseButton, { type: "button", onClick: onClick, children: _jsx(SystemIcon.XIcon, { color: Color.typography.blackMedium, size: 12 }) }));
91
88
  const BaseCloseButton = styled.button `
92
89
  display: flex;
93
90
  flex-direction: column;
94
91
 
95
- min-width: 12px;
92
+ min-width: ${Spacing.px12};
96
93
  `;
97
94
  //# sourceMappingURL=Badge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../core/molecules/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAgBlD,MAAM,KAAK,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,WAAW,EAAc,EAAE,EAAE;IACpE,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChD,OAAO,KAAC,QAAQ,OAAK,YAAY,KAAM,WAAW,GAAI,CAAC;AACzD,CAAC,CAAC;AAEF,eAAe,KAAK,CAAC;AAQrB,MAAM,iBAAiB,GAAqD;IAC1E,OAAO,EAAE;QACP,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;QACjC,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;QAC1C,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;KACzC;IACD,OAAO,EAAE;QACP,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;QACjC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK;QAC3C,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK;KAC1C;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;QACzB,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;QAC1C,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;KACzC;IACD,KAAK,EAAE;QACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;QAC1B,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;QAC3C,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;KAC1C;IACD,MAAM,EAAE;QACN,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;QAC3B,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;QAC5C,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;KAC3C;IACD,GAAG,EAAE;QACH,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;QACxB,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;QACzC,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;KACxC;CACF,CAAC;AAIF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,GAAG,sBAAsB,EAC7C,KAAK,GACS,EAAE,EAAE,CAAC,CACnB,MAAC,SAAS,IACR,OAAO,EAAE,OAAO,kBACF,CAAC,CAAC,OAAO,6BACE,sBAAsB,2BACxB,oBAAoB,YACnC,KAAK,aAEb,MAAC,YAAY,aAAQ,CAAC,CAAC,QAAQ,kBAAgB,gBAAgB,aAC5D,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,aAAa,cACZ,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAI,GAClB,CACjB,CAAC,CAAC,CAAC,CACF,mBAAK,CACN,EAED,KAAC,UAAU,cAAE,KAAK,GAAc,IACnB,EAEd,QAAQ,CAAC,CAAC,CAAC,KAAC,OAAO,IAAC,OAAO,EAAE,QAAQ,GAAI,CAAC,CAAC,CAAC,mBAAK,IACxC,CACb,CAAC;AAEF,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAK1B;;;;;;;iBAOe,OAAO,CAAC,IAAI;;;;iBAIZ,UAAU,CAAC,MAAM,CAAC,MAAM;;WAE9B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM;sBACZ,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,uBAAuB;;YAElD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;;;wBAGxC,CAAC,KAAK,EAAE,EAAE,CAC5B,KAAK,CAAC,YAAY;IAChB,CAAC,CAAC,KAAK,CAAC,qBAAqB;IAC7B,CAAC,CAAC,KAAK,CAAC,uBAAuB;;CAEtC,CAAC;AAEF,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAG7B;;;;;WAKS,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;eAC/D,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CACrC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM;CAC5C,CAAC;AAEF,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAiC;;;;WAItD,CAAC,EAAE,SAAS,GAAG,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS;eACjC,CAAC,EAAE,SAAS,GAAG,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS;eACrC,CAAC,EAAE,SAAS,GAAG,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS;CACnD,CAAC;AAEF,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;IAKzB,eAAe,CAAC,UAAU,CAAC,mBAAmB,CAAC;CAClD,CAAC;AAMF,MAAM,OAAO,GAAG,CAAC,EAAE,OAAO,EAAgB,EAAE,EAAE,CAAC,CAC7C,KAAC,eAAe,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,YAC7C,KAAC,UAAU,CAAC,KAAK,IAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,GAAI,GACnD,CACnB,CAAC;AAEF,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAA;;;;;CAKpC,CAAC","sourcesContent":["import type { ComponentType, MouseEventHandler, ReactNode } from \"react\";\nimport styled from \"styled-components\";\nimport { Color, Spacing, SystemIcon, Typography } from \"../atoms\";\nimport { applyTypography } from \"../integrations\";\n\ntype BadgeVariant = \"default\" | \"neutral\" | \"blue\" | \"green\" | \"yellow\" | \"red\";\n\ntype CustomBadgeProps = {\n label: ReactNode;\n Icon?: ComponentType<SystemIcon.IconProps>;\n onClick?: MouseEventHandler<HTMLDivElement>;\n onClickX?: MouseEventHandler<HTMLButtonElement>;\n labelWidthPixels?: number;\n};\n\ntype BadgeProps = {\n variant?: BadgeVariant;\n} & CustomBadgeProps;\n\nconst Badge = ({ variant = \"default\", ...restOfProps }: BadgeProps) => {\n const variantProps = VARIANT_PROPS_MAP[variant];\n return <RawBadge {...variantProps} {...restOfProps} />;\n};\n\nexport default Badge;\n\ntype VariantStyleProps = {\n color: Color.DesignColor;\n defaultBackgroundColor: Color.DesignColor;\n hoverBackgroundColor?: Color.DesignColor;\n};\n\nconst VARIANT_PROPS_MAP: { [variant in BadgeVariant]: VariantStyleProps } = {\n default: {\n color: Color.typography.blackHigh,\n defaultBackgroundColor: Color.accent.blue3,\n hoverBackgroundColor: Color.accent.blue4,\n },\n neutral: {\n color: Color.typography.blackHigh,\n defaultBackgroundColor: Color.neutral.grey4,\n hoverBackgroundColor: Color.neutral.grey3,\n },\n blue: {\n color: Color.accent.blue1,\n defaultBackgroundColor: Color.accent.blue3,\n hoverBackgroundColor: Color.accent.blue4,\n },\n green: {\n color: Color.accent.green1,\n defaultBackgroundColor: Color.accent.green3,\n hoverBackgroundColor: Color.accent.green4,\n },\n yellow: {\n color: Color.accent.yellow1,\n defaultBackgroundColor: Color.accent.yellow3,\n hoverBackgroundColor: Color.accent.yellow4,\n },\n red: {\n color: Color.accent.red1,\n defaultBackgroundColor: Color.accent.red3,\n hoverBackgroundColor: Color.accent.red4,\n },\n};\n\ntype RawBadgeProps = CustomBadgeProps & VariantStyleProps;\n\nexport const RawBadge = ({\n label,\n Icon,\n onClick,\n onClickX,\n labelWidthPixels,\n defaultBackgroundColor,\n hoverBackgroundColor = defaultBackgroundColor,\n color,\n}: RawBadgeProps) => (\n <BaseBadge\n onClick={onClick}\n $isClickable={!!onClick}\n $defaultBackgroundColor={defaultBackgroundColor}\n $hoverBackgroundColor={hoverBackgroundColor}\n $color={color}\n >\n <BadgeContent $hasX={!!onClickX} $widthPixels={labelWidthPixels}>\n {Icon ? (\n <IconContainer>\n <Icon color={color} size={12} />\n </IconContainer>\n ) : (\n <></>\n )}\n\n <BadgeLabel>{label}</BadgeLabel>\n </BadgeContent>\n\n {onClickX ? <XButton onClick={onClickX} /> : <></>}\n </BaseBadge>\n);\n\nconst BaseBadge = styled.div<{\n $isClickable: boolean;\n $defaultBackgroundColor: Color.DesignColor;\n $hoverBackgroundColor: Color.DesignColor;\n $color: Color.DesignColor;\n}>`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n\n height: 26px;\n padding: 5px ${Spacing.px12};\n border-radius: 100px;\n\n font-size: 12px;\n font-weight: ${Typography.weight.medium};\n\n color: ${(props) => props.$color};\n background-color: ${(props) => props.$defaultBackgroundColor};\n\n cursor: ${(props) => (props.$isClickable ? \"pointer\" : \"auto\")};\n\n &:hover {\n background-color: ${(props) =>\n props.$isClickable\n ? props.$hoverBackgroundColor\n : props.$defaultBackgroundColor};\n }\n`;\n\nconst BadgeContent = styled.div<{\n $hasX: boolean;\n $widthPixels?: number;\n}>`\n display: flex;\n align-items: center;\n gap: 10px;\n\n width: ${({ $widthPixels }) => ($widthPixels ? `${$widthPixels}px` : \"auto\")};\n max-width: ${({ $hasX: $closeable }) =>\n $closeable ? \"calc(100% - 20px)\" : \"auto\"};\n`;\n\nconst IconContainer = styled.div<{ $iconSize?: string | number }>`\n display: flex;\n flex-direction: column;\n\n width: ${({ $iconSize = \"auto\" }) => $iconSize};\n min-width: ${({ $iconSize = \"auto\" }) => $iconSize};\n max-width: ${({ $iconSize = \"auto\" }) => $iconSize};\n`;\n\nconst BadgeLabel = styled.div`\n overflow-x: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n\n ${applyTypography(Typography.bodySecondaryMedium)}\n`;\n\ntype XButtonProps = {\n onClick: MouseEventHandler<HTMLButtonElement>;\n};\n\nconst XButton = ({ onClick }: XButtonProps) => (\n <BaseCloseButton type=\"button\" onClick={onClick}>\n <SystemIcon.XIcon color={Color.typography.blackMedium} size={12} />\n </BaseCloseButton>\n);\n\nconst BaseCloseButton = styled.button`\n display: flex;\n flex-direction: column;\n\n min-width: 12px;\n`;\n"]}
1
+ {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../core/molecules/Badge.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentType, MouseEventHandler, ReactNode } from \"react\";\nimport styled from \"styled-components\";\nimport { Color, Spacing, SystemIcon, Typography } from \"../atoms\";\nimport { applyTypography } from \"../integrations\";\n\ntype BadgeVariant = \"default\" | \"neutral\" | \"blue\" | \"green\" | \"yellow\" | \"red\";\n\ntype CustomBadgeProps = {\n label: ReactNode;\n Icon?: ComponentType<SystemIcon.IconProps>;\n onClick?: MouseEventHandler<HTMLDivElement>;\n onClickX?: MouseEventHandler<HTMLButtonElement>;\n labelWidthPixels?: number;\n};\n\ntype BadgeProps = {\n variant?: BadgeVariant;\n} & CustomBadgeProps;\n\nconst Badge = ({ variant = \"default\", ...restOfProps }: BadgeProps) => {\n const variantProps = VARIANT_PROPS_MAP[variant];\n return <RawBadge {...variantProps} {...restOfProps} />;\n};\n\nexport default Badge;\n\ntype VariantStyleProps = {\n color: Color.DesignColor;\n defaultBackgroundColor: Color.DesignColor;\n hoverBackgroundColor?: Color.DesignColor;\n};\n\nconst VARIANT_PROPS_MAP: { [variant in BadgeVariant]: VariantStyleProps } = {\n default: {\n color: Color.typography.blackHigh,\n defaultBackgroundColor: Color.accent.blue3,\n hoverBackgroundColor: Color.accent.blue4,\n },\n neutral: {\n color: Color.typography.blackHigh,\n defaultBackgroundColor: Color.neutral.grey4,\n hoverBackgroundColor: Color.neutral.grey3,\n },\n blue: {\n color: Color.accent.blue1,\n defaultBackgroundColor: Color.accent.blue3,\n hoverBackgroundColor: Color.accent.blue4,\n },\n green: {\n color: Color.accent.green1,\n defaultBackgroundColor: Color.accent.green3,\n hoverBackgroundColor: Color.accent.green4,\n },\n yellow: {\n color: Color.accent.yellow1,\n defaultBackgroundColor: Color.accent.yellow3,\n hoverBackgroundColor: Color.accent.yellow4,\n },\n red: {\n color: Color.accent.red1,\n defaultBackgroundColor: Color.accent.red3,\n hoverBackgroundColor: Color.accent.red4,\n },\n};\n\ntype RawBadgeProps = CustomBadgeProps & VariantStyleProps;\n\nexport const RawBadge = ({\n label,\n Icon,\n onClick,\n onClickX,\n labelWidthPixels,\n defaultBackgroundColor,\n hoverBackgroundColor = defaultBackgroundColor,\n color,\n}: RawBadgeProps) => (\n <BaseBadge\n onClick={onClick}\n $isClickable={!!onClick}\n $defaultBackgroundColor={defaultBackgroundColor}\n $hoverBackgroundColor={hoverBackgroundColor}\n $color={color}\n >\n <BadgeContent $hasX={!!onClickX} $widthPixels={labelWidthPixels}>\n {Icon ? (\n <IconContainer>\n <Icon color={color} size={12} />\n </IconContainer>\n ) : (\n <></>\n )}\n\n <BadgeLabel>{label}</BadgeLabel>\n </BadgeContent>\n\n {onClickX ? <XButton onClick={onClickX} /> : <></>}\n </BaseBadge>\n);\n\nconst BaseBadge = styled.div<{\n $isClickable: boolean;\n $defaultBackgroundColor: Color.DesignColor;\n $hoverBackgroundColor: Color.DesignColor;\n $color: Color.DesignColor;\n}>`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${Spacing.px12};\n\n height: 26px;\n padding: 5px ${Spacing.px12};\n\n color: ${(props) => props.$color};\n background-color: ${(props) => props.$defaultBackgroundColor};\n border-radius: ${Spacing.px100};\n\n cursor: ${(props) => (props.$isClickable ? \"pointer\" : \"auto\")};\n\n &:hover {\n background-color: ${(props) =>\n props.$isClickable\n ? props.$hoverBackgroundColor\n : props.$defaultBackgroundColor};\n }\n`;\n\nconst BadgeContent = styled.div<{\n $hasX: boolean;\n $widthPixels?: number;\n}>`\n display: flex;\n align-items: center;\n gap: ${Spacing.px4};\n\n width: ${({ $widthPixels }) => ($widthPixels ? `${$widthPixels}px` : \"auto\")};\n max-width: ${({ $hasX: $closeable }) =>\n $closeable ? `calc(100% - ${Spacing.px20})` : \"auto\"};\n`;\n\nconst IconContainer = styled.div<{ $iconSize?: string | number }>`\n display: flex;\n flex-direction: column;\n\n width: ${({ $iconSize = \"auto\" }) => $iconSize};\n min-width: ${({ $iconSize = \"auto\" }) => $iconSize};\n max-width: ${({ $iconSize = \"auto\" }) => $iconSize};\n`;\n\nconst BadgeLabel = styled.div`\n overflow-x: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n\n ${applyTypography(Typography.captionMedium)}\n`;\n\ntype XButtonProps = {\n onClick: MouseEventHandler<HTMLButtonElement>;\n};\n\nconst XButton = ({ onClick }: XButtonProps) => (\n <BaseCloseButton type=\"button\" onClick={onClick}>\n <SystemIcon.XIcon color={Color.typography.blackMedium} size={12} />\n </BaseCloseButton>\n);\n\nconst BaseCloseButton = styled.button`\n display: flex;\n flex-direction: column;\n\n min-width: ${Spacing.px12};\n`;\n"]}
@@ -0,0 +1,20 @@
1
+ import { type HTMLAttributes, type PropsWithChildren, type ReactNode } from "react";
2
+ export type ToastVariant = "neutral" | "success" | "danger";
3
+ export type ToastProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "title"> & {
4
+ title?: ReactNode;
5
+ message?: ReactNode;
6
+ variant?: ToastVariant;
7
+ action?: {
8
+ label: ReactNode;
9
+ onClick: () => void;
10
+ };
11
+ onClose?: () => void;
12
+ };
13
+ declare const Toast: ({ title, message, variant, action, onClose, ...props }: ToastProps) => import("react").JSX.Element;
14
+ export default Toast;
15
+ export type ToastOptions = ToastProps & {
16
+ dedupeKey?: string;
17
+ duration?: number;
18
+ };
19
+ export declare const ToastProvider: ({ children }: PropsWithChildren) => import("react").JSX.Element;
20
+ export declare const useToast: () => (options: ToastOptions) => void;
@@ -0,0 +1,239 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useState, } from "react";
3
+ import styled, { keyframes } from "styled-components";
4
+ import { Color, Responsive, Spacing, SystemIcon, Typography } from "../atoms";
5
+ import { applyTypography } from "../integrations";
6
+ const toastVariants = {
7
+ neutral: {
8
+ iconBackground: Color.neutral.grey1,
9
+ border: Color.neutral.grey2,
10
+ background: Color.neutral.grey3,
11
+ Icon: null,
12
+ },
13
+ success: {
14
+ iconBackground: Color.accent.green1,
15
+ border: Color.accent.green2,
16
+ background: Color.accent.green4,
17
+ Icon: SystemIcon.CheckIcon,
18
+ },
19
+ danger: {
20
+ iconBackground: Color.accent.red1,
21
+ border: Color.accent.red2,
22
+ background: Color.accent.red4,
23
+ Icon: SystemIcon.XIcon,
24
+ },
25
+ };
26
+ const Toast = ({ title, message, variant = "neutral", action, onClose, ...props }) => {
27
+ const { iconBackground, border, background, Icon } = toastVariants[variant];
28
+ const isCompact = title == null && !action;
29
+ return (_jsxs(ToastContainer, { ...props, role: variant === "danger" ? "alert" : "status", "$border": border, "$background": background, "$compact": isCompact, children: [_jsxs(ToastLayout, { children: [_jsxs(ToastDetails, { children: [_jsx(ToastIconContainer, { "$background": iconBackground, children: Icon ? (_jsx(Icon, { color: Color.neutral.white, size: 14, weight: "bold" })) : (_jsx(SystemIcon.InfoIcon, { color: Color.neutral.white, size: 14, weight: "bold" })) }), _jsxs(ToastText, { children: [title != null && _jsx(Title, { children: title }), message != null && _jsx(Message, { children: message })] })] }), action && (_jsx(ActionButton, { type: "button", onClick: action.onClick, children: action.label }))] }), onClose && (_jsx(CloseButton, { type: "button", onClick: onClose, children: _jsx(SystemIcon.XIcon, { color: Color.typography.blackMedium, size: 18 }) }))] }));
30
+ };
31
+ export default Toast;
32
+ const ToastContext = createContext(null);
33
+ export const ToastProvider = ({ children }) => {
34
+ const [toasts, setToasts] = useState([]);
35
+ const dismissToast = useCallback((id) => setToasts((currentToasts) => currentToasts.filter((toast) => toast.id !== id)), []);
36
+ const showToast = useCallback((options) => setToasts((currentToasts) => {
37
+ const existingToastIndex = options.dedupeKey
38
+ ? currentToasts.findIndex((toast) => toast.dedupeKey === options.dedupeKey)
39
+ : -1;
40
+ const nextToast = existingToastIndex < 0
41
+ ? { ...options, id: crypto.randomUUID(), revision: 0 }
42
+ : {
43
+ ...currentToasts[existingToastIndex],
44
+ ...options,
45
+ revision: currentToasts[existingToastIndex].revision + 1,
46
+ };
47
+ return [
48
+ nextToast,
49
+ ...currentToasts.filter((_, toastIndex) => toastIndex !== existingToastIndex),
50
+ ].slice(0, 3);
51
+ }), []);
52
+ return (_jsxs(ToastContext.Provider, { value: showToast, children: [children, _jsx(Viewport, { "data-slot": "toast-viewport", "$stackDepth": Math.max(0, toasts.length - 1), children: toasts.map(({ id, revision, dedupeKey, duration = 8000, ...props }, index) => (_jsx(StackItem, { "data-pulse": revision > 0, "$index": index, children: _jsx(TimedToast, { ...props, id: id, duration: duration, dismiss: dismissToast }) }, `${dedupeKey ?? id}-${revision}`))) })] }));
53
+ };
54
+ export const useToast = () => {
55
+ const showToast = useContext(ToastContext);
56
+ if (!showToast)
57
+ throw new Error("useToast must be used within ToastProvider");
58
+ return showToast;
59
+ };
60
+ const TimedToast = ({ id, duration, dismiss, action, onClose, onMouseEnter, onMouseLeave, onFocus, onBlur, ...props }) => {
61
+ const [isTimerPaused, setIsTimerPaused] = useState(false);
62
+ useEffect(() => {
63
+ if (isTimerPaused)
64
+ return;
65
+ const timeoutId = window.setTimeout(() => dismiss(id), duration);
66
+ return () => window.clearTimeout(timeoutId);
67
+ }, [dismiss, duration, id, isTimerPaused]);
68
+ return (_jsx(Toast, { ...props, onMouseEnter: (event) => {
69
+ setIsTimerPaused(true);
70
+ onMouseEnter?.(event);
71
+ }, onMouseLeave: (event) => {
72
+ if (!event.currentTarget.contains(document.activeElement))
73
+ setIsTimerPaused(false);
74
+ onMouseLeave?.(event);
75
+ }, onFocus: (event) => {
76
+ setIsTimerPaused(true);
77
+ onFocus?.(event);
78
+ }, onBlur: (event) => {
79
+ if (!event.currentTarget.contains(event.relatedTarget) &&
80
+ !event.currentTarget.matches(":hover"))
81
+ setIsTimerPaused(false);
82
+ onBlur?.(event);
83
+ }, action: action && {
84
+ label: action.label,
85
+ onClick: () => {
86
+ dismiss(id);
87
+ action.onClick();
88
+ },
89
+ }, onClose: () => {
90
+ onClose?.();
91
+ dismiss(id);
92
+ } }));
93
+ };
94
+ const ToastContainer = styled.div `
95
+ display: flex;
96
+ align-items: center;
97
+ gap: ${Spacing.px16};
98
+
99
+ box-sizing: border-box;
100
+ width: ${({ $compact }) => ($compact ? "300px" : "400px")};
101
+ max-width: calc(100vw - ${Spacing.px40});
102
+ min-height: ${({ $compact }) => ($compact ? "44px" : "64px")};
103
+ padding: ${Spacing.px12};
104
+
105
+ background: ${({ $background }) => $background};
106
+ border: 1px solid ${({ $border }) => $border};
107
+ border-radius: ${Spacing.px8};
108
+ `;
109
+ const ToastLayout = styled.div `
110
+ display: flex;
111
+ align-items: flex-start;
112
+ gap: ${Spacing.px8};
113
+ flex: 1;
114
+
115
+ min-width: 0;
116
+ `;
117
+ const ToastDetails = styled.div `
118
+ display: flex;
119
+ align-items: flex-start;
120
+ gap: ${Spacing.px12};
121
+ flex: 1;
122
+
123
+ min-width: 0;
124
+ `;
125
+ const ToastIconContainer = styled.span `
126
+ display: grid;
127
+ place-items: center;
128
+ flex: 0 0 ${Spacing.px20};
129
+
130
+ height: ${Spacing.px20};
131
+
132
+ background: ${({ $background }) => $background};
133
+ border-radius: ${Spacing.px4};
134
+ `;
135
+ const ToastText = styled.div `
136
+ display: flex;
137
+ flex: 1;
138
+ flex-direction: column;
139
+ justify-content: center;
140
+
141
+ min-width: 0;
142
+ `;
143
+ const Title = styled.div `
144
+ color: ${Color.typography.blackHigh};
145
+
146
+ ${applyTypography(Typography.bodySecondaryBold)}
147
+ `;
148
+ const Message = styled.div `
149
+ color: ${Color.typography.blackMedium};
150
+
151
+ ${applyTypography(Typography.bodySecondaryRegular)}
152
+ `;
153
+ const ActionButton = styled.button `
154
+ align-self: center;
155
+ flex: none;
156
+
157
+ box-sizing: border-box;
158
+ height: ${Spacing.px40};
159
+ padding: 10px 0;
160
+
161
+ color: ${Color.typography.blackHigh};
162
+ background: transparent;
163
+
164
+ text-decoration: underline;
165
+ white-space: nowrap;
166
+
167
+ cursor: pointer;
168
+
169
+ ${applyTypography(Typography.bodySecondaryMedium)}
170
+ `;
171
+ const CloseButton = styled.button `
172
+ display: grid;
173
+ place-items: center;
174
+ align-self: center;
175
+ flex: 0 0 ${Spacing.px24};
176
+
177
+ width: ${Spacing.px24};
178
+ height: ${Spacing.px24};
179
+
180
+ background: transparent;
181
+
182
+ cursor: pointer;
183
+ `;
184
+ const toastPulse = keyframes `
185
+ 0%, 100% { transform: scale(1); }
186
+ 50% { transform: scale(1.03); }
187
+ `;
188
+ const StackItem = styled.div `
189
+ grid-area: 1 / 1;
190
+ z-index: ${({ $index }) => 3 - $index};
191
+
192
+ transform: translate(
193
+ ${({ $index }) => `${-$index * 8}px`},
194
+ ${({ $index }) => `${-$index * 8}px`}
195
+ );
196
+ transition: transform 250ms ease-in-out;
197
+ pointer-events: ${({ $index }) => ($index === 0 ? "auto" : "none")};
198
+
199
+ ${({ $index }) => $index > 0 &&
200
+ `
201
+ > [role] > * {
202
+ visibility: hidden;
203
+ }
204
+ `}
205
+
206
+ &[data-pulse="true"] > [role] {
207
+ animation: ${toastPulse} 250ms ease-in-out;
208
+ }
209
+
210
+ @media (prefers-reduced-motion: reduce) {
211
+ transition: none;
212
+
213
+ &[data-pulse="true"] > [role] {
214
+ animation: none;
215
+ }
216
+ }
217
+ `;
218
+ const Viewport = styled.div `
219
+ display: grid;
220
+ padding: ${({ $stackDepth }) => `${$stackDepth * 8}px 0 0 ${$stackDepth * 8}px`};
221
+
222
+ z-index: 100;
223
+ position: fixed;
224
+ top: 25px;
225
+ right: ${Spacing.px20};
226
+ transition: padding 250ms ease-in-out;
227
+
228
+ @media (prefers-reduced-motion: reduce) {
229
+ transition: none;
230
+ }
231
+
232
+ @media (width < ${Responsive.widthBreakpoint.laptop}) {
233
+ top: auto;
234
+ right: 50%;
235
+ bottom: var(--toast-mobile-bottom-offset, ${Spacing.px88});
236
+ transform: translateX(50%);
237
+ }
238
+ `;
239
+ //# sourceMappingURL=Toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toast.js","sourceRoot":"","sources":["../../../core/molecules/Toast.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n type HTMLAttributes,\n type PropsWithChildren,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\nimport styled, { keyframes } from \"styled-components\";\nimport { Color, Responsive, Spacing, SystemIcon, Typography } from \"../atoms\";\nimport { applyTypography } from \"../integrations\";\n\nexport type ToastVariant = \"neutral\" | \"success\" | \"danger\";\n\nexport type ToastProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\" | \"title\"\n> & {\n title?: ReactNode;\n message?: ReactNode;\n variant?: ToastVariant;\n action?: {\n label: ReactNode;\n onClick: () => void;\n };\n onClose?: () => void;\n};\n\nconst toastVariants = {\n neutral: {\n iconBackground: Color.neutral.grey1,\n border: Color.neutral.grey2,\n background: Color.neutral.grey3,\n Icon: null,\n },\n success: {\n iconBackground: Color.accent.green1,\n border: Color.accent.green2,\n background: Color.accent.green4,\n Icon: SystemIcon.CheckIcon,\n },\n danger: {\n iconBackground: Color.accent.red1,\n border: Color.accent.red2,\n background: Color.accent.red4,\n Icon: SystemIcon.XIcon,\n },\n} as const;\n\nconst Toast = ({\n title,\n message,\n variant = \"neutral\",\n action,\n onClose,\n ...props\n}: ToastProps) => {\n const { iconBackground, border, background, Icon } = toastVariants[variant];\n const isCompact = title == null && !action;\n\n return (\n <ToastContainer\n {...props}\n role={variant === \"danger\" ? \"alert\" : \"status\"}\n $border={border}\n $background={background}\n $compact={isCompact}\n >\n <ToastLayout>\n <ToastDetails>\n <ToastIconContainer $background={iconBackground}>\n {Icon ? (\n <Icon color={Color.neutral.white} size={14} weight=\"bold\" />\n ) : (\n <SystemIcon.InfoIcon\n color={Color.neutral.white}\n size={14}\n weight=\"bold\"\n />\n )}\n </ToastIconContainer>\n <ToastText>\n {title != null && <Title>{title}</Title>}\n {message != null && <Message>{message}</Message>}\n </ToastText>\n </ToastDetails>\n {action && (\n <ActionButton type=\"button\" onClick={action.onClick}>\n {action.label}\n </ActionButton>\n )}\n </ToastLayout>\n {onClose && (\n <CloseButton type=\"button\" onClick={onClose}>\n <SystemIcon.XIcon color={Color.typography.blackMedium} size={18} />\n </CloseButton>\n )}\n </ToastContainer>\n );\n};\n\nexport default Toast;\n\nexport type ToastOptions = ToastProps & {\n dedupeKey?: string;\n duration?: number;\n};\n\ntype ToastItem = ToastOptions & { id: string; revision: number };\n\nconst ToastContext = createContext<((options: ToastOptions) => void) | null>(\n null,\n);\n\nexport const ToastProvider = ({ children }: PropsWithChildren) => {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const dismissToast = useCallback(\n (id: string) =>\n setToasts((currentToasts) =>\n currentToasts.filter((toast) => toast.id !== id),\n ),\n [],\n );\n const showToast = useCallback(\n (options: ToastOptions) =>\n setToasts((currentToasts) => {\n const existingToastIndex = options.dedupeKey\n ? currentToasts.findIndex(\n (toast) => toast.dedupeKey === options.dedupeKey,\n )\n : -1;\n const nextToast =\n existingToastIndex < 0\n ? { ...options, id: crypto.randomUUID(), revision: 0 }\n : {\n ...currentToasts[existingToastIndex],\n ...options,\n revision: currentToasts[existingToastIndex].revision + 1,\n };\n\n return [\n nextToast,\n ...currentToasts.filter(\n (_, toastIndex) => toastIndex !== existingToastIndex,\n ),\n ].slice(0, 3);\n }),\n [],\n );\n\n return (\n <ToastContext.Provider value={showToast}>\n {children}\n <Viewport\n data-slot=\"toast-viewport\"\n $stackDepth={Math.max(0, toasts.length - 1)}\n >\n {toasts.map(\n ({ id, revision, dedupeKey, duration = 8000, ...props }, index) => (\n <StackItem\n key={`${dedupeKey ?? id}-${revision}`}\n data-pulse={revision > 0}\n $index={index}\n >\n <TimedToast\n {...props}\n id={id}\n duration={duration}\n dismiss={dismissToast}\n />\n </StackItem>\n ),\n )}\n </Viewport>\n </ToastContext.Provider>\n );\n};\n\nexport const useToast = () => {\n const showToast = useContext(ToastContext);\n if (!showToast) throw new Error(\"useToast must be used within ToastProvider\");\n return showToast;\n};\n\nconst TimedToast = ({\n id,\n duration,\n dismiss,\n action,\n onClose,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}: ToastOptions & { id: string; dismiss: (id: string) => void }) => {\n const [isTimerPaused, setIsTimerPaused] = useState(false);\n\n useEffect(() => {\n if (isTimerPaused) return;\n const timeoutId = window.setTimeout(() => dismiss(id), duration);\n return () => window.clearTimeout(timeoutId);\n }, [dismiss, duration, id, isTimerPaused]);\n\n return (\n <Toast\n {...props}\n onMouseEnter={(event) => {\n setIsTimerPaused(true);\n onMouseEnter?.(event);\n }}\n onMouseLeave={(event) => {\n if (!event.currentTarget.contains(document.activeElement))\n setIsTimerPaused(false);\n onMouseLeave?.(event);\n }}\n onFocus={(event) => {\n setIsTimerPaused(true);\n onFocus?.(event);\n }}\n onBlur={(event) => {\n if (\n !event.currentTarget.contains(event.relatedTarget) &&\n !event.currentTarget.matches(\":hover\")\n )\n setIsTimerPaused(false);\n onBlur?.(event);\n }}\n action={\n action && {\n label: action.label,\n onClick: () => {\n dismiss(id);\n action.onClick();\n },\n }\n }\n onClose={() => {\n onClose?.();\n dismiss(id);\n }}\n />\n );\n};\n\nconst ToastContainer = styled.div<{\n $border: Color.DesignColor;\n $background: Color.DesignColor;\n $compact: boolean;\n}>`\n display: flex;\n align-items: center;\n gap: ${Spacing.px16};\n\n box-sizing: border-box;\n width: ${({ $compact }) => ($compact ? \"300px\" : \"400px\")};\n max-width: calc(100vw - ${Spacing.px40});\n min-height: ${({ $compact }) => ($compact ? \"44px\" : \"64px\")};\n padding: ${Spacing.px12};\n\n background: ${({ $background }) => $background};\n border: 1px solid ${({ $border }) => $border};\n border-radius: ${Spacing.px8};\n`;\n\nconst ToastLayout = styled.div`\n display: flex;\n align-items: flex-start;\n gap: ${Spacing.px8};\n flex: 1;\n\n min-width: 0;\n`;\n\nconst ToastDetails = styled.div`\n display: flex;\n align-items: flex-start;\n gap: ${Spacing.px12};\n flex: 1;\n\n min-width: 0;\n`;\n\nconst ToastIconContainer = styled.span<{\n $background: Color.DesignColor;\n}>`\n display: grid;\n place-items: center;\n flex: 0 0 ${Spacing.px20};\n\n height: ${Spacing.px20};\n\n background: ${({ $background }) => $background};\n border-radius: ${Spacing.px4};\n`;\n\nconst ToastText = styled.div`\n display: flex;\n flex: 1;\n flex-direction: column;\n justify-content: center;\n\n min-width: 0;\n`;\n\nconst Title = styled.div`\n color: ${Color.typography.blackHigh};\n\n ${applyTypography(Typography.bodySecondaryBold)}\n`;\n\nconst Message = styled.div`\n color: ${Color.typography.blackMedium};\n\n ${applyTypography(Typography.bodySecondaryRegular)}\n`;\n\nconst ActionButton = styled.button`\n align-self: center;\n flex: none;\n\n box-sizing: border-box;\n height: ${Spacing.px40};\n padding: 10px 0;\n\n color: ${Color.typography.blackHigh};\n background: transparent;\n\n text-decoration: underline;\n white-space: nowrap;\n\n cursor: pointer;\n\n ${applyTypography(Typography.bodySecondaryMedium)}\n`;\n\nconst CloseButton = styled.button`\n display: grid;\n place-items: center;\n align-self: center;\n flex: 0 0 ${Spacing.px24};\n\n width: ${Spacing.px24};\n height: ${Spacing.px24};\n\n background: transparent;\n\n cursor: pointer;\n`;\n\nconst toastPulse = keyframes`\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.03); }\n`;\n\nconst StackItem = styled.div<{ $index: number }>`\n grid-area: 1 / 1;\n z-index: ${({ $index }) => 3 - $index};\n\n transform: translate(\n ${({ $index }) => `${-$index * 8}px`},\n ${({ $index }) => `${-$index * 8}px`}\n );\n transition: transform 250ms ease-in-out;\n pointer-events: ${({ $index }) => ($index === 0 ? \"auto\" : \"none\")};\n\n ${({ $index }) =>\n $index > 0 &&\n `\n > [role] > * {\n visibility: hidden;\n }\n `}\n\n &[data-pulse=\"true\"] > [role] {\n animation: ${toastPulse} 250ms ease-in-out;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n\n &[data-pulse=\"true\"] > [role] {\n animation: none;\n }\n }\n`;\n\nconst Viewport = styled.div<{ $stackDepth: number }>`\n display: grid;\n padding: ${({ $stackDepth }) =>\n `${$stackDepth * 8}px 0 0 ${$stackDepth * 8}px`};\n\n z-index: 100;\n position: fixed;\n top: 25px;\n right: ${Spacing.px20};\n transition: padding 250ms ease-in-out;\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n\n @media (width < ${Responsive.widthBreakpoint.laptop}) {\n top: auto;\n right: 50%;\n bottom: var(--toast-mobile-bottom-offset, ${Spacing.px88});\n transform: translateX(50%);\n }\n`;\n"]}
@@ -0,0 +1,21 @@
1
+ import { type ButtonHTMLAttributes, type HTMLAttributes } from "react";
2
+ export type ToggleButtonSize = "small" | "medium" | "large";
3
+ export type ToggleButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> & {
4
+ pressed?: boolean;
5
+ onPressedChange?: (isPressed: boolean) => void;
6
+ size?: ToggleButtonSize;
7
+ };
8
+ declare const ToggleButton: ({ pressed, onPressedChange, onClick, size, type, ...props }: ToggleButtonProps) => import("react").JSX.Element;
9
+ export default ToggleButton;
10
+ export type ToggleButtonGroupProps = Omit<HTMLAttributes<HTMLDivElement>, "defaultValue" | "onChange"> & {
11
+ disabled?: boolean;
12
+ size?: ToggleButtonSize;
13
+ value?: string;
14
+ defaultValue?: string;
15
+ onValueChange?: (value: string) => void;
16
+ };
17
+ export declare const ToggleButtonGroup: ({ children, value, defaultValue, onValueChange, disabled, size, ...props }: ToggleButtonGroupProps) => import("react").JSX.Element;
18
+ export type ToggleButtonGroupItemProps = Omit<ToggleButtonProps, "onPressedChange" | "pressed" | "size"> & {
19
+ value: string;
20
+ };
21
+ export declare const ToggleButtonGroupItem: ({ value, disabled, ...props }: ToggleButtonGroupItemProps) => import("react").JSX.Element;
@@ -0,0 +1,161 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo, useState, } from "react";
4
+ import styled from "styled-components";
5
+ import { Color, Typography } from "../atoms";
6
+ import { applyTypography } from "../integrations";
7
+ const toggleButtonSizeStyles = {
8
+ small: {
9
+ iconButtonSize: "26px",
10
+ textButtonHeight: "26px",
11
+ iconSize: "14px",
12
+ padding: "6px",
13
+ },
14
+ medium: {
15
+ iconButtonSize: "46px",
16
+ textButtonHeight: "48px",
17
+ iconSize: "20px",
18
+ padding: "13px",
19
+ },
20
+ large: {
21
+ iconButtonSize: "52px",
22
+ textButtonHeight: "56px",
23
+ iconSize: "20px",
24
+ padding: "16px",
25
+ },
26
+ };
27
+ const toggleButtonTypography = {
28
+ small: {
29
+ ...Typography.captionMedium,
30
+ fontSize: { small: "10px", large: "10px" },
31
+ },
32
+ medium: Typography.bodyPrimaryMedium,
33
+ large: Typography.subheading2Medium,
34
+ };
35
+ const ToggleButton = ({ pressed, onPressedChange, onClick, size = "medium", type = "button", ...props }) => {
36
+ const [isUncontrolledPressed, setIsUncontrolledPressed] = useState(false);
37
+ const isPressed = pressed ?? isUncontrolledPressed;
38
+ return (_jsx(ToggleButtonContainer, { ...props, type: type, "data-state": isPressed ? "on" : "off", "$size": size, onClick: (event) => {
39
+ onClick?.(event);
40
+ if (event.defaultPrevented)
41
+ return;
42
+ const shouldPress = !isPressed;
43
+ if (pressed === undefined)
44
+ setIsUncontrolledPressed(shouldPress);
45
+ onPressedChange?.(shouldPress);
46
+ } }));
47
+ };
48
+ export default ToggleButton;
49
+ const ToggleButtonGroupContext = createContext(null);
50
+ export const ToggleButtonGroup = ({ children, value, defaultValue, onValueChange, disabled = false, size = "medium", ...props }) => {
51
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? "");
52
+ const selectedValue = value ?? uncontrolledValue;
53
+ const contextValue = useMemo(() => ({
54
+ isGroupDisabled: disabled,
55
+ selectedValue,
56
+ groupSize: size,
57
+ toggleItem: (itemValue) => {
58
+ const nextSelectedValue = selectedValue === itemValue ? "" : itemValue;
59
+ if (value === undefined)
60
+ setUncontrolledValue(nextSelectedValue);
61
+ onValueChange?.(nextSelectedValue);
62
+ },
63
+ }), [disabled, onValueChange, selectedValue, size, value]);
64
+ return (_jsx(ToggleButtonGroupContext.Provider, { value: contextValue, children: _jsx(ToggleButtonGroupContainer, { ...props, role: "group", children: children }) }));
65
+ };
66
+ export const ToggleButtonGroupItem = ({ value, disabled, ...props }) => {
67
+ const groupContext = useContext(ToggleButtonGroupContext);
68
+ if (!groupContext)
69
+ throw new Error("ToggleButtonGroupItem must be used within ToggleButtonGroup");
70
+ return (_jsx(ToggleButton, { ...props, pressed: groupContext.selectedValue === value, disabled: groupContext.isGroupDisabled || disabled, size: groupContext.groupSize, onPressedChange: () => groupContext.toggleItem(value) }));
71
+ };
72
+ const ToggleButtonContainer = styled.button `
73
+ display: inline-flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ box-sizing: border-box;
77
+ min-width: ${({ $size }) => toggleButtonSizeStyles[$size].iconButtonSize};
78
+ height: ${({ $size }) => toggleButtonSizeStyles[$size].iconButtonSize};
79
+ padding: ${({ $size }) => toggleButtonSizeStyles[$size].padding};
80
+
81
+ ${({ $size }) => applyTypography(toggleButtonTypography[$size])}
82
+ white-space: nowrap;
83
+
84
+ color: ${Color.typography.blackHigh};
85
+ background: ${Color.neutral.white};
86
+ border: 1px solid ${Color.neutral.grey2};
87
+ border-radius: 6px;
88
+
89
+ cursor: pointer;
90
+
91
+ &:hover:not(:disabled):not([data-state="on"]) {
92
+ background: ${Color.accent.blue3};
93
+ }
94
+
95
+ &[data-state="on"] {
96
+ position: relative;
97
+ z-index: 1;
98
+
99
+ color: ${Color.typography.whiteHigh};
100
+ background: ${Color.brand.grantbiiBlue};
101
+ border-color: ${Color.brand.grantbiiBlue};
102
+
103
+ &:hover:not(:disabled) {
104
+ background: ${Color.accent.blue2};
105
+ border-color: ${Color.accent.blue2};
106
+ }
107
+ }
108
+
109
+ &:focus-visible {
110
+ position: relative;
111
+ z-index: 2;
112
+ outline: 2px solid ${Color.accent.blue2};
113
+ outline-offset: 2px;
114
+ }
115
+
116
+ &:disabled {
117
+ color: ${Color.typography.blackMedium};
118
+ background: ${Color.neutral.grey2};
119
+ cursor: not-allowed;
120
+ }
121
+
122
+ svg {
123
+ flex: none;
124
+ width: ${({ $size }) => toggleButtonSizeStyles[$size].iconSize};
125
+ height: ${({ $size }) => toggleButtonSizeStyles[$size].iconSize};
126
+ }
127
+
128
+ &:not(:has(svg)) {
129
+ height: ${({ $size }) => toggleButtonSizeStyles[$size].textButtonHeight};
130
+ }
131
+ `;
132
+ const ToggleButtonGroupContainer = styled.div `
133
+ display: inline-flex;
134
+ box-sizing: border-box;
135
+
136
+ border-radius: 6px;
137
+ outline: 1px solid ${Color.neutral.grey2};
138
+ outline-offset: -1px;
139
+
140
+ > button {
141
+ border: 0;
142
+ border-radius: 0;
143
+ }
144
+
145
+ > button:not(:last-child) {
146
+ border-right: 1px solid ${Color.neutral.grey2};
147
+ }
148
+
149
+ > button:first-child {
150
+ border-radius: 6px 0 0 6px;
151
+ }
152
+
153
+ > button:last-child {
154
+ border-radius: 0 6px 6px 0;
155
+ }
156
+
157
+ > button:only-child {
158
+ border-radius: 6px;
159
+ }
160
+ `;
161
+ //# sourceMappingURL=ToggleButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleButton.js","sourceRoot":"","sources":["../../../core/molecules/ToggleButton.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useMemo,\n useState,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n} from \"react\";\nimport styled from \"styled-components\";\nimport { Color, Typography } from \"../atoms\";\nimport { applyTypography } from \"../integrations\";\n\nexport type ToggleButtonSize = \"small\" | \"medium\" | \"large\";\n\nconst toggleButtonSizeStyles: Record<\n ToggleButtonSize,\n {\n iconButtonSize: string;\n textButtonHeight: string;\n iconSize: string;\n padding: string;\n }\n> = {\n small: {\n iconButtonSize: \"26px\",\n textButtonHeight: \"26px\",\n iconSize: \"14px\",\n padding: \"6px\",\n },\n medium: {\n iconButtonSize: \"46px\",\n textButtonHeight: \"48px\",\n iconSize: \"20px\",\n padding: \"13px\",\n },\n large: {\n iconButtonSize: \"52px\",\n textButtonHeight: \"56px\",\n iconSize: \"20px\",\n padding: \"16px\",\n },\n};\n\nconst toggleButtonTypography: Record<ToggleButtonSize, Typography.TextStyle> = {\n small: {\n ...Typography.captionMedium,\n fontSize: { small: \"10px\", large: \"10px\" },\n },\n medium: Typography.bodyPrimaryMedium,\n large: Typography.subheading2Medium,\n};\n\nexport type ToggleButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"onChange\"\n> & {\n pressed?: boolean;\n onPressedChange?: (isPressed: boolean) => void;\n size?: ToggleButtonSize;\n};\n\nconst ToggleButton = ({\n pressed,\n onPressedChange,\n onClick,\n size = \"medium\",\n type = \"button\",\n ...props\n}: ToggleButtonProps) => {\n const [isUncontrolledPressed, setIsUncontrolledPressed] = useState(false);\n const isPressed = pressed ?? isUncontrolledPressed;\n\n return (\n <ToggleButtonContainer\n {...props}\n type={type}\n data-state={isPressed ? \"on\" : \"off\"}\n $size={size}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n\n const shouldPress = !isPressed;\n if (pressed === undefined) setIsUncontrolledPressed(shouldPress);\n onPressedChange?.(shouldPress);\n }}\n />\n );\n};\n\nexport default ToggleButton;\n\nexport type ToggleButtonGroupProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n \"defaultValue\" | \"onChange\"\n> & {\n disabled?: boolean;\n size?: ToggleButtonSize;\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n};\n\ntype ToggleButtonGroupContextValue = {\n isGroupDisabled: boolean;\n selectedValue: string;\n groupSize: ToggleButtonSize;\n toggleItem: (itemValue: string) => void;\n};\n\nconst ToggleButtonGroupContext =\n createContext<ToggleButtonGroupContextValue | null>(null);\n\nexport const ToggleButtonGroup = ({\n children,\n value,\n defaultValue,\n onValueChange,\n disabled = false,\n size = \"medium\",\n ...props\n}: ToggleButtonGroupProps) => {\n const [uncontrolledValue, setUncontrolledValue] = useState(\n defaultValue ?? \"\",\n );\n const selectedValue = value ?? uncontrolledValue;\n const contextValue = useMemo<ToggleButtonGroupContextValue>(\n () => ({\n isGroupDisabled: disabled,\n selectedValue,\n groupSize: size,\n toggleItem: (itemValue) => {\n const nextSelectedValue = selectedValue === itemValue ? \"\" : itemValue;\n if (value === undefined) setUncontrolledValue(nextSelectedValue);\n onValueChange?.(nextSelectedValue);\n },\n }),\n [disabled, onValueChange, selectedValue, size, value],\n );\n\n return (\n <ToggleButtonGroupContext.Provider value={contextValue}>\n <ToggleButtonGroupContainer {...props} role=\"group\">\n {children}\n </ToggleButtonGroupContainer>\n </ToggleButtonGroupContext.Provider>\n );\n};\n\nexport type ToggleButtonGroupItemProps = Omit<\n ToggleButtonProps,\n \"onPressedChange\" | \"pressed\" | \"size\"\n> & {\n value: string;\n};\n\nexport const ToggleButtonGroupItem = ({\n value,\n disabled,\n ...props\n}: ToggleButtonGroupItemProps) => {\n const groupContext = useContext(ToggleButtonGroupContext);\n if (!groupContext)\n throw new Error(\n \"ToggleButtonGroupItem must be used within ToggleButtonGroup\",\n );\n\n return (\n <ToggleButton\n {...props}\n pressed={groupContext.selectedValue === value}\n disabled={groupContext.isGroupDisabled || disabled}\n size={groupContext.groupSize}\n onPressedChange={() => groupContext.toggleItem(value)}\n />\n );\n};\n\nconst ToggleButtonContainer = styled.button<{ $size: ToggleButtonSize }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: ${({ $size }) => toggleButtonSizeStyles[$size].iconButtonSize};\n height: ${({ $size }) => toggleButtonSizeStyles[$size].iconButtonSize};\n padding: ${({ $size }) => toggleButtonSizeStyles[$size].padding};\n\n ${({ $size }) => applyTypography(toggleButtonTypography[$size])}\n white-space: nowrap;\n\n color: ${Color.typography.blackHigh};\n background: ${Color.neutral.white};\n border: 1px solid ${Color.neutral.grey2};\n border-radius: 6px;\n\n cursor: pointer;\n\n &:hover:not(:disabled):not([data-state=\"on\"]) {\n background: ${Color.accent.blue3};\n }\n\n &[data-state=\"on\"] {\n position: relative;\n z-index: 1;\n\n color: ${Color.typography.whiteHigh};\n background: ${Color.brand.grantbiiBlue};\n border-color: ${Color.brand.grantbiiBlue};\n\n &:hover:not(:disabled) {\n background: ${Color.accent.blue2};\n border-color: ${Color.accent.blue2};\n }\n }\n\n &:focus-visible {\n position: relative;\n z-index: 2;\n outline: 2px solid ${Color.accent.blue2};\n outline-offset: 2px;\n }\n\n &:disabled {\n color: ${Color.typography.blackMedium};\n background: ${Color.neutral.grey2};\n cursor: not-allowed;\n }\n\n svg {\n flex: none;\n width: ${({ $size }) => toggleButtonSizeStyles[$size].iconSize};\n height: ${({ $size }) => toggleButtonSizeStyles[$size].iconSize};\n }\n\n &:not(:has(svg)) {\n height: ${({ $size }) => toggleButtonSizeStyles[$size].textButtonHeight};\n }\n`;\n\nconst ToggleButtonGroupContainer = styled.div`\n display: inline-flex;\n box-sizing: border-box;\n\n border-radius: 6px;\n outline: 1px solid ${Color.neutral.grey2};\n outline-offset: -1px;\n\n > button {\n border: 0;\n border-radius: 0;\n }\n\n > button:not(:last-child) {\n border-right: 1px solid ${Color.neutral.grey2};\n }\n\n > button:first-child {\n border-radius: 6px 0 0 6px;\n }\n\n > button:last-child {\n border-radius: 0 6px 6px 0;\n }\n\n > button:only-child {\n border-radius: 6px;\n }\n`;\n"]}
@@ -0,0 +1,20 @@
1
+ import { type HTMLAttributes, type PropsWithChildren, type ReactElement } from "react";
2
+ export type TooltipSide = "top" | "right" | "bottom" | "left";
3
+ export type TooltipProps = PropsWithChildren<{
4
+ open?: boolean;
5
+ defaultOpen?: boolean;
6
+ onOpenChange?: (open: boolean) => void;
7
+ }>;
8
+ declare const Tooltip: ({ children, open: isControlledOpen, defaultOpen, onOpenChange, }: TooltipProps) => import("react").JSX.Element;
9
+ export default Tooltip;
10
+ export type TooltipTriggerProps = {
11
+ children: ReactElement<{
12
+ "aria-describedby"?: string;
13
+ }>;
14
+ };
15
+ export declare const TooltipTrigger: ({ children }: TooltipTriggerProps) => import("react").JSX.Element;
16
+ export type TooltipContentProps = PropsWithChildren<Omit<HTMLAttributes<HTMLDivElement>, "content"> & {
17
+ side?: TooltipSide;
18
+ sideOffset?: number;
19
+ }>;
20
+ export declare const TooltipContent: ({ children, side, sideOffset, ...props }: TooltipContentProps) => import("react").ReactPortal | null;