diff --git a/docs/components/example/index.json b/docs/components/example/index.json
index f1a2ba4b7..bdc730f71 100644
--- a/docs/components/example/index.json
+++ b/docs/components/example/index.json
@@ -141,6 +141,8 @@
"select-box-radio-preview": "import { SelectBoxRadioGroup, SelectBoxRadio } from \"seed-design/ui/select-box\";\n\nexport default function SelectBoxRadioPreview() {\n return (\n \n \n \n \n \n );\n}",
"skeleton-preview": "import { Flex } from \"seed-design/ui/layout\";\nimport { Skeleton } from \"seed-design/ui/skeleton\";\n\nexport default function SkeletonPreview() {\n return (\n \n \n \n \n \n \n \n );\n}",
"skeleton-radius": "import { Skeleton } from \"seed-design/ui/skeleton\";\nimport { Flex } from \"seed-design/ui/layout\";\n\nexport default function SkeletonRadius() {\n return (\n \n \n \n \n \n \n );\n}",
+ "snackbar-avoid-overlap": "import { Flex } from \"@/registry/ui/layout\";\nimport { ActionButton } from \"seed-design/ui/action-button\";\nimport {\n Snackbar,\n SnackbarAvoidOverlap,\n SnackbarProvider,\n useSnackbarAdapter,\n} from \"seed-design/ui/snackbar\";\n\nfunction Component() {\n const adapter = useSnackbarAdapter();\n\n return (\n \n \n adapter.create({\n timeout: 5000,\n onClose: () => {},\n render: () => {}} />,\n })\n }\n >\n 실행\n \n \n \n Snackbar가 이 영역과 겹치지 않게 조정됩니다. 스크롤은 무시합니다.\n \n \n \n );\n}\n\nexport default function SnackbarPreview() {\n return (\n \n \n \n );\n}",
+ "snackbar-preview": "import { ActionButton } from \"seed-design/ui/action-button\";\nimport { Snackbar, SnackbarProvider, useSnackbarAdapter } from \"seed-design/ui/snackbar\";\n\nfunction Component() {\n const adapter = useSnackbarAdapter();\n\n return (\n \n adapter.create({\n timeout: 5000,\n onClose: () => {},\n render: () => {}} />,\n })\n }\n >\n 실행\n \n );\n}\n\nexport default function SnackbarPreview() {\n return (\n \n \n \n );\n}",
"switch-disabled": "import { Switch } from \"seed-design/ui/switch\";\n\nexport default function SwitchDisabled() {\n return (\n
\n \n \n
\n );\n}",
"switch-medium": "import { useState } from \"react\";\nimport { Switch } from \"seed-design/ui/switch\";\n\nexport default function SwitchMedium() {\n const [isChecked, setIsChecked] = useState(false);\n\n return ;\n}",
"switch-preview": "import { useState } from \"react\";\nimport { Switch } from \"seed-design/ui/switch\";\n\nexport default function SwitchPreview() {\n const [isChecked, setIsChecked] = useState(false);\n\n return ;\n}",
diff --git a/docs/public/__registry__/ui/action-button.json b/docs/public/__registry__/ui/action-button.json
index 771c5c7d0..aef11b39b 100644
--- a/docs/public/__registry__/ui/action-button.json
+++ b/docs/public/__registry__/ui/action-button.json
@@ -7,7 +7,7 @@
{
"name": "action-button.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/progressCircle.css\";\n// TODO: we have to ensure load order between actionButton.css and progressCircle.css. should we bundle them together?\nimport \"@seed-design/stylesheet/actionButton.css\";\n\nimport { ActionButton as SeedActionButton } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nexport interface ActionButtonProps extends SeedActionButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/action-button\n */\nexport const ActionButton = React.forwardRef<\n React.ElementRef,\n ActionButtonProps\n>(\n (\n {\n loading = false,\n layout = \"withText\",\n prefixIcon,\n suffixIcon,\n children,\n ...otherProps\n },\n ref,\n ) => {\n return (\n \n {layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {suffixIcon && }\n >\n ) : (\n \n )}\n {loading ? : null}\n \n );\n },\n);\nActionButton.displayName = \"ActionButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/actionButton.css\";\n\nimport { ActionButton as SeedActionButton } from \"@seed-design/react\";\nimport * as React from \"react\";\nimport { ProgressCircle } from \"./progress-circle\";\n\nexport interface ActionButtonProps extends SeedActionButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/action-button\n */\nexport const ActionButton = React.forwardRef<\n React.ElementRef,\n ActionButtonProps\n>(\n (\n {\n loading = false,\n layout = \"withText\",\n prefixIcon,\n suffixIcon,\n children,\n ...otherProps\n },\n ref,\n ) => {\n return (\n \n {layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {suffixIcon && }\n >\n ) : (\n \n )}\n {loading ? (\n \n \n \n ) : null}\n \n );\n },\n);\nActionButton.displayName = \"ActionButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/action-chip.json b/docs/public/__registry__/ui/action-chip.json
index 6360a89b3..0932205ba 100644
--- a/docs/public/__registry__/ui/action-chip.json
+++ b/docs/public/__registry__/ui/action-chip.json
@@ -7,7 +7,7 @@
{
"name": "action-chip.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport { ActionChip as SeedActionChip } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nimport \"@seed-design/stylesheet/actionChip.css\";\n\nexport interface ActionChipProps extends SeedActionChip.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n count?: number;\n}\n\nexport const ActionChip = React.forwardRef(\n ({ children, prefixIcon, suffixIcon, count, ...otherProps }, ref) => {\n return (\n \n {otherProps.layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {count && {count}}\n {suffixIcon && }\n >\n ) : (\n \n )}\n \n );\n },\n);\nActionChip.displayName = \"ActionChip\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport { ActionChip as SeedActionChip } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nimport \"@seed-design/stylesheet/actionChip.css\";\n\nexport interface ActionChipProps extends SeedActionChip.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n count?: number;\n}\n\nexport const ActionChip = React.forwardRef(\n (\n {\n children,\n prefixIcon,\n suffixIcon,\n count,\n layout = \"withText\",\n ...otherProps\n },\n ref,\n ) => {\n return (\n \n {layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {count && {count}}\n {suffixIcon && }\n >\n ) : (\n \n )}\n \n );\n },\n);\nActionChip.displayName = \"ActionChip\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/control-chip.json b/docs/public/__registry__/ui/control-chip.json
index 5c11b250c..92485e1a2 100644
--- a/docs/public/__registry__/ui/control-chip.json
+++ b/docs/public/__registry__/ui/control-chip.json
@@ -7,7 +7,7 @@
{
"name": "control-chip.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport { ControlChip as SeedControlChip } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nimport \"@seed-design/stylesheet/controlChip.css\";\n\nexport interface ControlChipToggleProps extends SeedControlChip.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n count?: number;\n}\n\nexport const ControlChipToggle = React.forwardRef<\n HTMLLabelElement,\n ControlChipToggleProps\n>(({ children, prefixIcon, suffixIcon, count, ...otherProps }, ref) => {\n return (\n \n {otherProps.layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {count && {count}}\n {suffixIcon && }\n >\n ) : (\n \n )}\n \n );\n});\nControlChipToggle.displayName = \"ControlChip.Toggle\";\n\nexport const ControlChip = Object.assign(\n () => {\n console.warn(\n \"ControlChip is a base component and should not be rendered. Use ControlChip.Toggle or ControlChip.Radio instead.\",\n );\n },\n {\n Toggle: ControlChipToggle,\n },\n);\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport { ControlChip as SeedControlChip } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nimport \"@seed-design/stylesheet/controlChip.css\";\n\nexport interface ControlChipToggleProps extends SeedControlChip.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n count?: number;\n}\n\nexport const ControlChipToggle = React.forwardRef<\n HTMLLabelElement,\n ControlChipToggleProps\n>(\n (\n {\n children,\n prefixIcon,\n suffixIcon,\n count,\n layout = \"withText\",\n ...otherProps\n },\n ref,\n ) => {\n return (\n \n {layout === \"withText\" ? (\n <>\n {prefixIcon && }\n {children}\n {count && {count}}\n {suffixIcon && }\n >\n ) : (\n \n )}\n \n );\n },\n);\nControlChipToggle.displayName = \"ControlChip.Toggle\";\n\nexport const ControlChip = Object.assign(\n () => {\n console.warn(\n \"ControlChip is a base component and should not be rendered. Use ControlChip.Toggle or ControlChip.Radio instead.\",\n );\n },\n {\n Toggle: ControlChipToggle,\n },\n);\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/help-bubble.json b/docs/public/__registry__/ui/help-bubble.json
index 6379f62d8..63531601c 100644
--- a/docs/public/__registry__/ui/help-bubble.json
+++ b/docs/public/__registry__/ui/help-bubble.json
@@ -8,7 +8,7 @@
{
"name": "help-bubble.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/helpBubble.css\";\n\nimport IconXmarkLine from \"@daangn/react-monochrome-icon/IconXmarkLine\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { usePopover, type UsePopoverProps } from \"@seed-design/react-popover\";\nimport { helpBubble } from \"@seed-design/recipe/helpBubble\";\nimport { createContext, forwardRef, useContext } from \"react\";\nimport { mergeRefs } from \"../util/mergeRefs\";\n\ninterface HelpBubbleArrowProps extends React.ComponentPropsWithRef<\"svg\"> {\n width: number;\n\n height: number;\n\n tipRadius: number;\n}\n\nconst HelpBubbleArrow = forwardRef(\n (props, ref) => {\n const { width, height, tipRadius, ...otherProps } = props;\n const pathData = `M0,0\n H${width}\n L${width / 2 + tipRadius},${height - tipRadius}\n Q${width / 2},${height} ${width / 2 - tipRadius},${height - tipRadius}\n Z`;\n\n return (\n \n );\n },\n);\n\nconst HelpBubbleContext = createContext<{\n api: ReturnType;\n} | null>(null);\n\nexport interface HelpBubbleTriggerProps extends UsePopoverProps {\n title: string;\n\n description?: string;\n\n showCloseButton?: boolean;\n\n children?: React.ReactNode;\n}\n\nexport const HelpBubbleTrigger = forwardRef<\n HTMLButtonElement,\n HelpBubbleTriggerProps\n>((props, ref) => {\n const {\n open,\n defaultOpen,\n onOpenChange,\n placement = \"top\",\n gutter = 4,\n overflowPadding = 16,\n arrowPadding = 14,\n flip = true,\n slide = true,\n strategy = \"absolute\",\n showCloseButton = false,\n title,\n description,\n ...otherProps\n } = props;\n\n const api = usePopover({\n open,\n defaultOpen,\n onOpenChange,\n placement,\n gutter,\n overflowPadding,\n arrowPadding,\n flip,\n slide,\n strategy,\n });\n const classNames = helpBubble();\n\n const arrowRect = api.rects.arrow;\n\n return (\n <>\n \n {api.open && (\n \n {showCloseButton ? (\n
\n ) : null}\n
\n
\n \n
\n
{props.title}\n {props.description && (\n
\n {props.description}\n \n )}\n
\n
\n )}\n >\n );\n});\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/helpBubble.css\";\n\nimport IconXmarkLine from \"@daangn/react-monochrome-icon/IconXmarkLine\";\nimport { HelpBubble as SeedHelpBubble } from \"@seed-design/react\";\nimport { forwardRef } from \"react\";\n\nexport interface HelpBubbleTriggerProps\n extends Omit {\n title: string;\n\n description?: string;\n\n showCloseButton?: boolean;\n\n children?: React.ReactNode;\n\n contentProps?: SeedHelpBubble.ContentProps;\n}\n\nexport const HelpBubbleTrigger = forwardRef<\n HTMLButtonElement,\n HelpBubbleTriggerProps\n>((props, ref) => {\n const {\n showCloseButton = false,\n title,\n description,\n contentProps,\n children,\n ...otherProps\n } = props;\n\n return (\n \n \n {children}\n \n \n \n {showCloseButton ? (\n \n } />\n \n ) : null}\n \n \n \n {props.title}\n {props.description && (\n \n {props.description}\n \n )}\n \n \n \n );\n});\n\nexport interface HelpBubbleAnchorProps\n extends Omit {\n title: string;\n\n description?: string;\n\n showCloseButton?: boolean;\n\n children?: React.ReactNode;\n}\n\nexport const HelpBubbleAnchor = forwardRef<\n HTMLDivElement,\n HelpBubbleAnchorProps\n>((props, ref) => {\n const {\n open,\n defaultOpen,\n onOpenChange,\n showCloseButton = false,\n title,\n description,\n ...otherProps\n } = props;\n\n return (\n \n \n \n \n {showCloseButton ? (\n \n } />\n \n ) : null}\n \n \n \n {props.title}\n {props.description && (\n \n {props.description}\n \n )}\n \n \n \n );\n});\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/index.json b/docs/public/__registry__/ui/index.json
index 8576787ec..b71936870 100644
--- a/docs/public/__registry__/ui/index.json
+++ b/docs/public/__registry__/ui/index.json
@@ -168,6 +168,16 @@
"ui:inline-banner.tsx"
]
},
+ {
+ "name": "snackbar",
+ "dependencies": [
+ "@seed-design/react",
+ "@daangn/react-monochrome-icon"
+ ],
+ "files": [
+ "ui:snackbar.tsx"
+ ]
+ },
{
"name": "help-bubble",
"dependencies": [
diff --git a/docs/public/__registry__/ui/progress-circle.json b/docs/public/__registry__/ui/progress-circle.json
index 9285ca270..c01892a3e 100644
--- a/docs/public/__registry__/ui/progress-circle.json
+++ b/docs/public/__registry__/ui/progress-circle.json
@@ -7,7 +7,7 @@
{
"name": "progress-circle.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/progressCircle.css\";\n\nimport {\n ProgressCircle as SeedProgressCircle,\n type ProgressCircleProps as SeedProgressCircleProps,\n} from \"@seed-design/react\";\n\nexport interface ProgressCircleProps extends SeedProgressCircleProps {}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/progress-circle\n */\nexport const ProgressCircle = SeedProgressCircle;\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/progressCircle.css\";\n\nimport { ProgressCircle as SeedProgressCircle } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nexport interface ProgressCircleProps extends SeedProgressCircle.RootProps {}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/progress-circle\n */\nexport const ProgressCircle = React.forwardRef<\n SVGSVGElement,\n ProgressCircleProps\n>((props, ref) => {\n return (\n \n \n \n \n );\n});\n\nProgressCircle.displayName = \"ProgressCircle\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/reaction-button.json b/docs/public/__registry__/ui/reaction-button.json
index 46e13ac2c..3aa7a3280 100644
--- a/docs/public/__registry__/ui/reaction-button.json
+++ b/docs/public/__registry__/ui/reaction-button.json
@@ -7,7 +7,7 @@
{
"name": "reaction-button.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/progressCircle.css\";\n// TODO: we have to ensure load order between reactionButton.css and progressCircle.css. should we bundle them together?\nimport \"@seed-design/stylesheet/reactionButton.css\";\n\nimport { ReactionButton as SeedReactionButton } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nexport interface ReactionButtonProps extends SeedReactionButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n count?: number;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/reaction-button\n */\nexport const ReactionButton = React.forwardRef<\n React.ElementRef,\n ReactionButtonProps\n>(({ loading = false, prefixIcon, count, children, ...otherProps }, ref) => {\n return (\n \n {prefixIcon && }\n {children}\n {count}\n {loading ? : null}\n \n );\n});\nReactionButton.displayName = \"ReactionButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/reactionButton.css\";\n\nimport { ReactionButton as SeedReactionButton } from \"@seed-design/react\";\nimport * as React from \"react\";\nimport { ProgressCircle } from \"./progress-circle\";\n\nexport interface ReactionButtonProps extends SeedReactionButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n count?: number;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/reaction-button\n */\nexport const ReactionButton = React.forwardRef<\n React.ElementRef,\n ReactionButtonProps\n>(({ loading = false, prefixIcon, count, children, ...otherProps }, ref) => {\n return (\n \n {prefixIcon && }\n {children}\n {count}\n {loading ? (\n \n \n \n ) : null}\n \n );\n});\nReactionButton.displayName = \"ReactionButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/snackbar.json b/docs/public/__registry__/ui/snackbar.json
new file mode 100644
index 000000000..ae8c91231
--- /dev/null
+++ b/docs/public/__registry__/ui/snackbar.json
@@ -0,0 +1,14 @@
+{
+ "name": "snackbar",
+ "dependencies": [
+ "@seed-design/react",
+ "@daangn/react-monochrome-icon"
+ ],
+ "registries": [
+ {
+ "name": "snackbar.tsx",
+ "type": "ui",
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/snackbar.css\";\n\nimport {\n Snackbar as SeedSnackbar,\n useSnackbarAdapter as useSeedSnackbarAdapter,\n useSnackbarContext,\n type CreateSnackbarOptions as SeedCreateSnackbarOptions,\n} from \"@seed-design/react\";\nimport * as React from \"react\";\n\nimport IconCheckmarkCircleFill from \"@daangn/react-monochrome-icon/IconCheckmarkCircleFill\";\nimport IconExclamationmarkCircleFill from \"@daangn/react-monochrome-icon/IconExclamationmarkCircleFill\";\n\nexport interface SnackbarProviderProps extends SeedSnackbar.RootProviderProps {}\n\nexport const SnackbarProvider = (props: SnackbarProviderProps) => {\n const { children, ...otherProps } = props;\n return (\n \n {children}\n \n \n \n \n );\n};\n\nexport interface SnackbarProps extends SeedSnackbar.RootProps {\n message: string;\n\n actionLabel: string;\n\n onAction: () => void;\n\n /**\n * @default true\n */\n shouldCloseOnAction?: boolean;\n}\n\nexport const Snackbar = React.forwardRef(\n (\n {\n variant = \"default\",\n children,\n message,\n actionLabel,\n onAction,\n shouldCloseOnAction = true,\n ...otherProps\n },\n ref,\n ) => {\n const api = useSnackbarContext();\n\n const handleAction: React.MouseEventHandler = (e) => {\n e.stopPropagation();\n onAction();\n if (shouldCloseOnAction) {\n e.currentTarget.blur();\n api.dismiss();\n }\n };\n\n return (\n \n \n ) : variant === \"danger\" ? (\n \n ) : null\n }\n />\n {message}\n \n {actionLabel}\n \n \n \n );\n },\n);\nSnackbar.displayName = \"Snackbar\";\n\n// TODO: re-export is ugly; should we namespace CreateSnackbarOptions into Snackbar?\nexport interface CreateSnackbarOptions extends SeedCreateSnackbarOptions {}\n\nexport const useSnackbarAdapter = useSeedSnackbarAdapter;\n\nexport const SnackbarAvoidOverlap = SeedSnackbar.AvoidOverlap;\n"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/text-button.json b/docs/public/__registry__/ui/text-button.json
index 156da680c..b2351c2b5 100644
--- a/docs/public/__registry__/ui/text-button.json
+++ b/docs/public/__registry__/ui/text-button.json
@@ -7,7 +7,7 @@
{
"name": "text-button.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/textButton.css\";\n\nimport * as React from \"react\";\nimport clsx from \"clsx\";\nimport {\n textButton,\n type TextButtonVariantProps,\n} from \"@seed-design/recipe/textButton\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nexport type TextButtonProps = TextButtonVariantProps &\n React.ButtonHTMLAttributes &\n ({\n /**\n * @default false\n */\n asChild?: boolean;\n } & (\n | { prefixIcon: React.ReactNode; suffixIcon?: never }\n | { prefixIcon?: never; suffixIcon: React.ReactNode }\n ));\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/text-button\n */\nexport const TextButton = React.forwardRef(\n (\n {\n asChild = false,\n className,\n tone = \"brand\",\n size = \"medium\",\n prefixIcon,\n suffixIcon,\n children,\n ...otherProps\n },\n ref,\n ) => {\n const classNames = textButton({ tone, size });\n\n return (\n \n );\n },\n);\nTextButton.displayName = \"TextButton\";\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/textButton.css\";\n\nimport { TextButton as SeedTextButton } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nexport type TextButtonProps = SeedTextButton.RootProps &\n (\n | { prefixIcon: React.ReactNode; suffixIcon?: never }\n | { prefixIcon?: never; suffixIcon: React.ReactNode }\n );\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/text-button\n */\nexport const TextButton = React.forwardRef(\n ({ prefixIcon, suffixIcon, children, ...otherProps }, ref) => {\n return (\n \n {prefixIcon && }\n {children}\n {suffixIcon && }\n \n );\n },\n);\nTextButton.displayName = \"TextButton\";\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/text-field.json b/docs/public/__registry__/ui/text-field.json
index b6f8e4bc6..2a96d8c39 100644
--- a/docs/public/__registry__/ui/text-field.json
+++ b/docs/public/__registry__/ui/text-field.json
@@ -9,7 +9,7 @@
{
"name": "text-field.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/textField.css\";\n\nimport * as React from \"react\";\nimport { IconExclamationmarkCircleFill } from \"@daangn/react-monochrome-icon\";\nimport { TextField as SeedTextField } from \"@seed-design/react\";\n\nexport interface TextFieldProps\n extends Omit {\n label?: React.ReactNode;\n\n indicator?: React.ReactNode;\n\n prefixIcon?: React.ReactNode;\n\n prefix?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n suffix?: React.ReactNode;\n\n description?: React.ReactNode;\n\n errorMessage?: React.ReactNode;\n\n hideCharacterCount?: boolean;\n}\n\nexport const TextField = React.forwardRef(\n (\n {\n description,\n errorMessage,\n prefix,\n prefixIcon,\n suffix,\n suffixIcon,\n indicator,\n label,\n children,\n hideCharacterCount,\n ...otherProps\n },\n ref,\n ) => {\n const renderCharacterCount =\n !hideCharacterCount && otherProps.maxGraphemeCount;\n const renderDescription = description && !otherProps.invalid;\n const renderErrorMessage = errorMessage && otherProps.invalid;\n const renderFooter =\n renderDescription || renderErrorMessage || renderCharacterCount;\n const renderHeader = label || indicator;\n\n return (\n \n {renderHeader && (\n \n {label}\n {indicator}\n \n )}\n \n {prefixIcon && }\n {prefix && (\n {prefix}\n )}\n {children}\n {suffix && (\n {suffix}\n )}\n {suffixIcon && }\n {indicator && (\n {indicator}\n )}\n \n {renderFooter && (\n \n {renderDescription && (\n \n {description}\n \n )}\n {renderErrorMessage && (\n \n }\n />\n {errorMessage}\n \n )}\n {renderCharacterCount && (\n \n \n \n /{otherProps.maxGraphemeCount}\n \n \n )}\n \n )}\n \n );\n },\n);\nTextField.displayName = \"TextField\";\n\nexport interface TextFieldInputProps extends SeedTextField.InputProps {}\n\nexport const TextFieldInput = SeedTextField.Input;\n\nexport interface TextFieldTextareaProps extends SeedTextField.TextareaProps {}\n\nexport const TextFieldTextarea = SeedTextField.Textarea;\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/textField.css\";\n\nimport * as React from \"react\";\nimport { IconExclamationmarkCircleFill } from \"@daangn/react-monochrome-icon\";\nimport { TextField as SeedTextField } from \"@seed-design/react\";\n\nexport interface TextFieldProps\n extends Omit {\n label?: React.ReactNode;\n\n indicator?: React.ReactNode;\n\n prefixIcon?: React.ReactNode;\n\n prefix?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n\n suffix?: React.ReactNode;\n\n description?: React.ReactNode;\n\n errorMessage?: React.ReactNode;\n\n hideCharacterCount?: boolean;\n}\n\nexport const TextField = React.forwardRef(\n (\n {\n description,\n errorMessage,\n prefix,\n prefixIcon,\n suffix,\n suffixIcon,\n indicator,\n label,\n children,\n hideCharacterCount,\n ...otherProps\n },\n ref,\n ) => {\n const renderCharacterCount =\n !hideCharacterCount && otherProps.maxGraphemeCount;\n const renderDescription = description && !otherProps.invalid;\n const renderErrorMessage = errorMessage && otherProps.invalid;\n const renderFooter =\n renderDescription || renderErrorMessage || renderCharacterCount;\n const renderHeader = label || indicator;\n\n return (\n \n {renderHeader && (\n \n {label}\n {indicator}\n \n )}\n \n {prefixIcon && }\n {prefix && (\n {prefix}\n )}\n {children}\n {suffix && (\n {suffix}\n )}\n {suffixIcon && }\n \n {renderFooter && (\n \n {renderDescription && (\n \n {description}\n \n )}\n {renderErrorMessage && (\n \n }\n />\n {errorMessage}\n \n )}\n {renderCharacterCount && (\n \n \n \n /{otherProps.maxGraphemeCount}\n \n \n )}\n \n )}\n \n );\n },\n);\nTextField.displayName = \"TextField\";\n\nexport interface TextFieldInputProps extends SeedTextField.InputProps {}\n\nexport const TextFieldInput = SeedTextField.Input;\n\nexport interface TextFieldTextareaProps extends SeedTextField.TextareaProps {}\n\nexport const TextFieldTextarea = SeedTextField.Textarea;\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/__registry__/ui/toggle-button.json b/docs/public/__registry__/ui/toggle-button.json
index a788bb3ce..4c42e1619 100644
--- a/docs/public/__registry__/ui/toggle-button.json
+++ b/docs/public/__registry__/ui/toggle-button.json
@@ -7,7 +7,7 @@
{
"name": "toggle-button.tsx",
"type": "ui",
- "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/progressCircle.css\";\n// TODO: we have to ensure load order between toggleButton.css and progressCircle.css. should we bundle them together?\nimport \"@seed-design/stylesheet/toggleButton.css\";\n\nimport { ToggleButton as SeedToggleButton } from \"@seed-design/react\";\nimport * as React from \"react\";\n\nexport interface ToggleButtonProps extends SeedToggleButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/toggle-button\n */\nexport const ToggleButton = React.forwardRef<\n React.ElementRef,\n ToggleButtonProps\n>(\n (\n { loading = false, prefixIcon, suffixIcon, children, ...otherProps },\n ref,\n ) => {\n return (\n \n {prefixIcon && }\n {children}\n {suffixIcon && }\n {loading ? : null}\n \n );\n },\n);\nToggleButton.displayName = \"ToggleButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
+ "content": "\"use client\";\n\nimport \"@seed-design/stylesheet/toggleButton.css\";\n\nimport { ToggleButton as SeedToggleButton } from \"@seed-design/react\";\nimport * as React from \"react\";\nimport { ProgressCircle } from \"./progress-circle\";\n\nexport interface ToggleButtonProps extends SeedToggleButton.RootProps {\n prefixIcon?: React.ReactNode;\n\n suffixIcon?: React.ReactNode;\n}\n\n/**\n * @see https://v3.seed-design.io/docs/react/components/toggle-button\n */\nexport const ToggleButton = React.forwardRef<\n React.ElementRef,\n ToggleButtonProps\n>(\n (\n { loading = false, prefixIcon, suffixIcon, children, ...otherProps },\n ref,\n ) => {\n return (\n \n {prefixIcon && }\n {children}\n {suffixIcon && }\n {loading ? (\n \n \n \n ) : null}\n \n );\n },\n);\nToggleButton.displayName = \"ToggleButton\";\n\n/**\n * This file is generated snippet from the Seed Design.\n * You can extend the functionality from this snippet if needed.\n */\n"
}
]
}
\ No newline at end of file
diff --git a/docs/public/rootage/components/snackbar.json b/docs/public/rootage/components/snackbar.json
new file mode 100644
index 000000000..a1b22d144
--- /dev/null
+++ b/docs/public/rootage/components/snackbar.json
@@ -0,0 +1,65 @@
+{
+ "kind": "ComponentSpec",
+ "metadata": {
+ "id": "snackbar",
+ "name": "Snackbar"
+ },
+ "data": {
+ "base": {
+ "enabled": {
+ "region": {
+ "paddingX": "$unit.s2",
+ "paddingY": "$unit.s2",
+ "offsetDuration": "$duration.s4",
+ "offsetTimingFunction": "$timing-function.easing"
+ },
+ "root": {
+ "color": "$color.bg.floating-solid",
+ "cornerRadius": "$radius.s2",
+ "minHeight": "44px",
+ "paddingX": "$unit.s4",
+ "paddingY": "$unit.s2_5",
+ "gap": "$unit.s2",
+ "enterOpacity": 0,
+ "enterDuration": "$duration.s4",
+ "enterTimingFunction": "$timing-function.enter",
+ "exitOpacity": 0,
+ "exitDuration": "$duration.s4",
+ "exitTimingFunction": "$timing-function.exit"
+ },
+ "message": {
+ "color": "$color.palette.static-white",
+ "fontSize": "$font-size.s4",
+ "lineHeight": "$line-height.s4",
+ "fontWeight": "$font-weight.regular"
+ },
+ "prefixIcon": {
+ "size": "24px"
+ },
+ "actionButton": {
+ "targetPaddingX": "$unit.s2",
+ "targetMinHeight": "44px",
+ "color": "$color.fg.brand",
+ "fontSize": "$font-size.s4",
+ "lineHeight": "$line-height.s4",
+ "fontWeight": "$font-weight.bold"
+ }
+ }
+ },
+ "variant=default": {},
+ "variant=positive": {
+ "enabled": {
+ "prefixIcon": {
+ "color": "$color.fg.positive"
+ }
+ }
+ },
+ "variant=danger": {
+ "enabled": {
+ "prefixIcon": {
+ "color": "$color.fg.danger"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/public/rootage/parsed.json b/docs/public/rootage/parsed.json
index bf90cae2c..3fdf7e7f1 100644
--- a/docs/public/rootage/parsed.json
+++ b/docs/public/rootage/parsed.json
@@ -19861,6 +19861,376 @@
}
]
},
+ {
+ "id": "snackbar",
+ "name": "Snackbar",
+ "data": [
+ {
+ "key": {},
+ "state": [
+ {
+ "key": [
+ "enabled"
+ ],
+ "slot": [
+ {
+ "key": "region",
+ "property": [
+ {
+ "key": "paddingX",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s2"
+ }
+ },
+ {
+ "key": "paddingY",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s2"
+ }
+ },
+ {
+ "key": "offsetDuration",
+ "value": {
+ "type": "token",
+ "group": [
+ "duration"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "offsetTimingFunction",
+ "value": {
+ "type": "token",
+ "group": [
+ "timing-function"
+ ],
+ "key": "easing"
+ }
+ }
+ ]
+ },
+ {
+ "key": "root",
+ "property": [
+ {
+ "key": "color",
+ "value": {
+ "type": "token",
+ "group": [
+ "color",
+ "bg"
+ ],
+ "key": "floating-solid"
+ }
+ },
+ {
+ "key": "cornerRadius",
+ "value": {
+ "type": "token",
+ "group": [
+ "radius"
+ ],
+ "key": "s2"
+ }
+ },
+ {
+ "key": "minHeight",
+ "value": {
+ "type": "dimension",
+ "value": 44,
+ "unit": "px"
+ }
+ },
+ {
+ "key": "paddingX",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "paddingY",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s2_5"
+ }
+ },
+ {
+ "key": "gap",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s2"
+ }
+ },
+ {
+ "key": "enterOpacity",
+ "value": {
+ "type": "number",
+ "value": 0
+ }
+ },
+ {
+ "key": "enterDuration",
+ "value": {
+ "type": "token",
+ "group": [
+ "duration"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "enterTimingFunction",
+ "value": {
+ "type": "token",
+ "group": [
+ "timing-function"
+ ],
+ "key": "enter"
+ }
+ },
+ {
+ "key": "exitOpacity",
+ "value": {
+ "type": "number",
+ "value": 0
+ }
+ },
+ {
+ "key": "exitDuration",
+ "value": {
+ "type": "token",
+ "group": [
+ "duration"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "exitTimingFunction",
+ "value": {
+ "type": "token",
+ "group": [
+ "timing-function"
+ ],
+ "key": "exit"
+ }
+ }
+ ]
+ },
+ {
+ "key": "message",
+ "property": [
+ {
+ "key": "color",
+ "value": {
+ "type": "token",
+ "group": [
+ "color",
+ "palette"
+ ],
+ "key": "static-white"
+ }
+ },
+ {
+ "key": "fontSize",
+ "value": {
+ "type": "token",
+ "group": [
+ "font-size"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "lineHeight",
+ "value": {
+ "type": "token",
+ "group": [
+ "line-height"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "fontWeight",
+ "value": {
+ "type": "token",
+ "group": [
+ "font-weight"
+ ],
+ "key": "regular"
+ }
+ }
+ ]
+ },
+ {
+ "key": "prefixIcon",
+ "property": [
+ {
+ "key": "size",
+ "value": {
+ "type": "dimension",
+ "value": 24,
+ "unit": "px"
+ }
+ }
+ ]
+ },
+ {
+ "key": "actionButton",
+ "property": [
+ {
+ "key": "targetPaddingX",
+ "value": {
+ "type": "token",
+ "group": [
+ "unit"
+ ],
+ "key": "s2"
+ }
+ },
+ {
+ "key": "targetMinHeight",
+ "value": {
+ "type": "dimension",
+ "value": 44,
+ "unit": "px"
+ }
+ },
+ {
+ "key": "color",
+ "value": {
+ "type": "token",
+ "group": [
+ "color",
+ "fg"
+ ],
+ "key": "brand"
+ }
+ },
+ {
+ "key": "fontSize",
+ "value": {
+ "type": "token",
+ "group": [
+ "font-size"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "lineHeight",
+ "value": {
+ "type": "token",
+ "group": [
+ "line-height"
+ ],
+ "key": "s4"
+ }
+ },
+ {
+ "key": "fontWeight",
+ "value": {
+ "type": "token",
+ "group": [
+ "font-weight"
+ ],
+ "key": "bold"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "key": {
+ "variant": "default"
+ },
+ "state": []
+ },
+ {
+ "key": {
+ "variant": "positive"
+ },
+ "state": [
+ {
+ "key": [
+ "enabled"
+ ],
+ "slot": [
+ {
+ "key": "prefixIcon",
+ "property": [
+ {
+ "key": "color",
+ "value": {
+ "type": "token",
+ "group": [
+ "color",
+ "fg"
+ ],
+ "key": "positive"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "key": {
+ "variant": "danger"
+ },
+ "state": [
+ {
+ "key": [
+ "enabled"
+ ],
+ "slot": [
+ {
+ "key": "prefixIcon",
+ "property": [
+ {
+ "key": "color",
+ "value": {
+ "type": "token",
+ "group": [
+ "color",
+ "fg"
+ ],
+ "key": "danger"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
{
"id": "switch",
"name": "Switch",