diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml
index 5a4bab67..60ffb959 100644
--- a/.github/ISSUE_TEMPLATE/feature.yml
+++ b/.github/ISSUE_TEMPLATE/feature.yml
@@ -1,7 +1,7 @@
name: Feature request 💄
description: Suggest a new idea for one of the packages.
labels: ['enhancement', 'needs triage']
-title: '[Feature?]: '
+title: '[Feat?]: '
body:
- type: markdown
attributes:
diff --git a/docs/app/components/MatchSideNavItem.tsx b/docs/app/components/MatchSideNavItem.tsx
index 9861c460..153e9bf2 100644
--- a/docs/app/components/MatchSideNavItem.tsx
+++ b/docs/app/components/MatchSideNavItem.tsx
@@ -17,7 +17,7 @@ export default function MatchSideNavItem(props: HeadingItem | LinkItem) {
return (
) {
w: 'full',
})}
>
- {props.navList.map((item) => (
+ {props.navList.map((item, idx) => (
diff --git a/docs/app/data/categories.json b/docs/app/data/categories.json
index 9bc1359d..1ccf130b 100644
--- a/docs/app/data/categories.json
+++ b/docs/app/data/categories.json
@@ -7,7 +7,7 @@
"communication": {
"name": "Communication",
"description": "Communication components provide useful information.",
- "items": ["Tag", "Tooltip", "Notification"]
+ "items": ["Notification", "Tag", "Tooltip"]
},
"containment": {
"name": "Containment",
diff --git a/docs/app/preset/side-nav.json b/docs/app/preset/side-nav.json
index 340c14ae..47f6aee0 100644
--- a/docs/app/preset/side-nav.json
+++ b/docs/app/preset/side-nav.json
@@ -20,14 +20,14 @@
"id": "2:a",
"label": "Theme",
"route": "/preset/theme",
- "tag": "new",
+ "tag": "",
"type": "route"
},
{
"id": "2:b",
"label": "Colors",
"route": "/preset/colors",
- "tag": "new",
+ "tag": "next",
"type": "route"
},
{
@@ -41,7 +41,7 @@
"id": "2:d",
"label": "Animation",
"route": "/preset/animation",
- "tag": "new",
+ "tag": "",
"type": "route"
},
{
diff --git a/docs/app/react/notification/components/messages.data.json b/docs/app/react/notification/components/messages.data.json
index c00a80cf..b0e1e195 100644
--- a/docs/app/react/notification/components/messages.data.json
+++ b/docs/app/react/notification/components/messages.data.json
@@ -15,7 +15,7 @@
"palette": "warning",
"id": "3",
"heading": "Slow Network",
- "description": "Your network is slow. Please check your connection."
+ "description": "Please check your connection."
},
{
"palette": "danger",
diff --git a/docs/app/react/side-nav.json b/docs/app/react/side-nav.json
index 08e9170a..82b2e378 100644
--- a/docs/app/react/side-nav.json
+++ b/docs/app/react/side-nav.json
@@ -1,203 +1,197 @@
[
{
- "id": "1",
"label": "Overview",
"type": "heading"
},
{
- "id": "1:a",
"label": "Getting Started",
"route": "/react",
"tag": "",
"type": "route"
},
{
- "id": "2",
- "label": "Components",
+ "label": "Actions",
"type": "heading"
},
{
- "id": "2:a",
"label": "Button",
"route": "/react/button",
"tag": "",
"type": "route"
},
{
- "id": "2:b",
"label": "Icon Button",
"route": "/react/icon-button",
"tag": "",
"type": "route"
},
{
- "id": "2:c",
- "label": "Label",
- "route": "/react/label",
+ "label": "Communication",
+ "type": "heading"
+ },
+ {
+ "label": "Notification",
+ "route": "/react/notification",
+ "tag": "next",
+ "type": "route"
+ },
+ {
+ "label": "Tag",
+ "route": "/react/tags",
"tag": "",
"type": "route"
},
{
- "id": "2:d",
- "label": "Input",
- "route": "/react/input",
+ "label": "Tooltip",
+ "route": "/react/tooltip",
"tag": "",
"type": "route"
},
{
- "id": "2:e",
- "label": "Field Message",
- "route": "/react/field-message",
+ "label": "Containment",
+ "type": "heading"
+ },
+ {
+ "label": "Confirm Modal",
+ "route": "/react/confirm-modal",
"tag": "",
"type": "route"
},
{
- "id": "2:f",
- "label": "Nav Menu",
- "route": "/react/nav-menu",
+ "label": "Prompt Modal",
+ "route": "/react/prompt-modal",
"tag": "",
"type": "route"
},
{
- "id": "2:g",
- "label": "Radio",
- "route": "/react/radio",
+ "label": "Modal",
+ "route": "/react/modal",
+ "tag": "",
+ "type": "route"
+ },
+ {
+ "label": "Navigation",
+ "type": "heading"
+ },
+ {
+ "label": "Nav Menu",
+ "route": "/react/nav-menu",
"tag": "",
"type": "route"
},
{
- "id": "2:h",
"label": "Tabs",
"route": "/react/tabs",
- "tag": "new",
+ "tag": "",
"type": "route"
},
{
- "id": "2:i",
- "label": "Tag",
- "route": "/react/tags",
- "tag": "",
+ "label": "Selection",
+ "type": "heading"
+ },
+ {
+ "label": "Drag & Drop",
+ "route": "/react/drag-n-drop",
+ "tag": "next",
"type": "route"
},
{
- "id": "2:j",
- "label": "Textarea",
- "route": "/react/textarea",
+ "label": "Radio",
+ "route": "/react/radio",
"tag": "",
"type": "route"
},
{
- "id": "2:k",
"label": "Toggle",
"route": "/react/toggle",
"tag": "",
"type": "route"
},
{
- "id": "2:l",
- "label": "Tooltip",
- "route": "/react/tooltip",
+ "label": "Forms",
+ "type": "heading"
+ },
+ {
+ "label": "Field Message",
+ "route": "/react/field-message",
"tag": "",
"type": "route"
},
{
- "id": "2:m",
- "label": "Confirm Modal",
- "route": "/react/confirm-modal",
- "tag": "new",
+ "label": "File Uploader",
+ "route": "/react/file-uploader",
+ "tag": "next",
"type": "route"
},
{
- "id": "2:n",
- "label": "Prompt Modal",
- "route": "/react/prompt-modal",
- "tag": "new",
+ "label": "Input",
+ "route": "/react/input",
+ "tag": "",
"type": "route"
},
{
- "id": "2:o",
- "label": "Modal",
- "route": "/react/modal",
- "tag": "new",
+ "label": "Label",
+ "route": "/react/label",
+ "tag": "",
"type": "route"
},
{
- "id": "2:p",
- "label": "Notification",
- "route": "/react/notification",
- "tag": "next",
+ "label": "Textarea",
+ "route": "/react/textarea",
+ "tag": "",
"type": "route"
},
{
- "id": "2:q",
+ "label": "Rendering",
+ "type": "heading"
+ },
+ {
"label": "Show",
"route": "/react/show",
"tag": "",
"type": "route"
},
{
- "id": "2:qr",
"label": "Portal",
"route": "/react/portal",
- "tag": "new",
+ "tag": "",
"type": "route"
},
{
- "id": "2:r",
"label": "Feature Flags",
"route": "/react/feature-flags",
- "tag": "new",
- "type": "route"
- },
- {
- "id": "2:s",
- "label": "File Uploader",
- "route": "/react/file-uploader",
- "tag": "next",
- "type": "route"
- },
- {
- "id": "2:t",
- "label": "Drag & Drop",
- "route": "/react/drag-n-drop",
- "tag": "next",
+ "tag": "",
"type": "route"
},
{
- "id": "3",
"label": "Hooks",
"type": "heading"
},
{
- "id": "3:a",
"label": "useModal",
"route": "/react/use-modal",
- "tag": "new",
+ "tag": "",
"type": "route"
},
{
- "id": "3:b",
"label": "useTheme",
"route": "/react/use-theme",
"tag": "",
"type": "route"
},
{
- "id": "3:c",
"label": "useThemeContext",
"route": "/react/use-theme-context",
"tag": "",
"type": "route"
},
{
- "id": "3:d",
"label": "useToggle",
"route": "/react/use-toggle",
"tag": "",
"type": "route"
},
{
- "id": "4",
"label": "Helpers",
"type": "heading"
},
@@ -205,7 +199,7 @@
"id": "4:a",
"label": "trapFocus",
"route": "/react/trap-focus",
- "tag": "new",
+ "tag": "",
"type": "route"
}
]
diff --git a/packages/panda-preset/src/recipes/slots/notification.ts b/packages/panda-preset/src/recipes/slots/notification.ts
index 6fb8bfda..e4cac03a 100644
--- a/packages/panda-preset/src/recipes/slots/notification.ts
+++ b/packages/panda-preset/src/recipes/slots/notification.ts
@@ -7,6 +7,8 @@ import {
WARNING,
} from '../shared/palettes'
import { focusStates } from '../shared/states'
+import { iconButton } from '../iconButton'
+import { button } from '../button'
/**
* This module contains the notification recipe.
@@ -22,6 +24,7 @@ function getNotificationPalette(
icon: statePalette,
heading: statePalette,
description: statePalette,
+ close: statePalette,
}
}
@@ -33,7 +36,15 @@ function getNotificationPalette(
export const notification: Partial = defineSlotRecipe({
className: 'notification',
description: 'The styles for Notification components',
- slots: ['center', 'dialog', 'icon', 'heading', 'description'],
+ slots: [
+ 'center',
+ 'dialog',
+ 'icon',
+ 'heading',
+ 'description',
+ 'close',
+ 'closeAll',
+ ],
jsx: [
'NotificationCenter',
'Notification',
@@ -45,14 +56,16 @@ export const notification: Partial = defineSlotRecipe({
base: {
center: {
- // combine with vstack
+ color: 'colorPalette.text.initial',
position: 'fixed',
right: '4',
- top: '4',
+ textAlign: 'right',
+ top: '24',
zIndex: 'toast',
},
dialog: {
bgColor: 'colorPalette.surface.initial',
+ color: 'colorPalette.text.initial',
maxW: '29rem',
minH: '3.125rem',
opacity: '0',
@@ -73,13 +86,13 @@ export const notification: Partial = defineSlotRecipe({
paddingInlineStart: '4',
},
heading: {
- color: 'colorPalette.text.initial',
+ color: 'inherit',
textStyle: 'label-md',
fontWeight: '600',
userSelect: 'none',
},
description: {
- color: 'colorPalette.text.initial',
+ color: 'inherit',
textStyle: 'body-sm',
userSelect: 'none',
['& :is(a)']: {
@@ -88,6 +101,25 @@ export const notification: Partial = defineSlotRecipe({
...focusStates,
},
},
+ close: {
+ ...iconButton.base,
+ bgColor: 'transparent',
+ color: 'inherit',
+ _hover: {
+ bgColor: 'colorPalette.bg.hover',
+ },
+ },
+ closeAll: {
+ ...button.base,
+ bgColor: 'transparent',
+ color: 'action.text.inverse',
+ height: '2.75rem',
+ pxi: '0',
+ _hover: {
+ bgColor: 'transparent',
+ color: 'action.bg.hover',
+ },
+ },
},
variants: {
@@ -95,7 +127,15 @@ export const notification: Partial = defineSlotRecipe({
[INFO]: getNotificationPalette(INFO),
[SUCCESS]: getNotificationPalette(SUCCESS),
[WARNING]: getNotificationPalette(WARNING),
- [DANGER]: getNotificationPalette(DANGER),
+ [DANGER]: {
+ ...getNotificationPalette(DANGER),
+ close: {
+ ...getNotificationPalette(DANGER).close,
+ _hover: {
+ color: 'danger.text.inverse',
+ },
+ },
+ },
},
},
diff --git a/packages/panda-preset/src/theme/semantic-tokens/info.ts b/packages/panda-preset/src/theme/semantic-tokens/info.ts
index 59db1683..253c36fa 100644
--- a/packages/panda-preset/src/theme/semantic-tokens/info.ts
+++ b/packages/panda-preset/src/theme/semantic-tokens/info.ts
@@ -1,5 +1,6 @@
import type { Prominence, SemanticToken } from './types'
-import { colors, deepGetByPaths, rawTokens } from '../../tokens'
+import { colors, deepGetByPaths, rawTokens, semanticColors } from '../../tokens'
+import { INFO } from '../../recipes/shared/palettes'
/**
* This module is a collection of info tokens that are used to generate the theme.
@@ -15,6 +16,8 @@ export interface InfoTokens {
}
readonly bg: {
readonly initial: SemanticToken
+ readonly hover: SemanticToken
+ readonly active: SemanticToken
}
readonly surface: {
readonly initial: SemanticToken
@@ -31,7 +34,9 @@ export const infoTokens: InfoTokens = {
info: {
border: {
initial: {
- description: 'The default border color of informational elements.',
+ description:
+ semanticColors.border[INFO].initial.$description ||
+ 'The default border color of informational elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -53,7 +58,9 @@ export const infoTokens: InfoTokens = {
bg: {
initial: {
- description: 'The default background color of informational elements.',
+ description:
+ semanticColors.background[INFO].initial.$description ||
+ 'The default background color of informational elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -71,11 +78,54 @@ export const infoTokens: InfoTokens = {
},
},
},
+ hover: {
+ description:
+ semanticColors.background[INFO].hover.$description ||
+ 'The hover background color of informational elements.',
+ value: {
+ _cerberusTheme: {
+ base: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.info.hover.$value,
+ ).$value,
+ _lightMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.light.background.info.hover.$value,
+ ).$value,
+ _darkMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.info.hover.$value,
+ ).$value,
+ },
+ },
+ },
+ active: {
+ description:
+ semanticColors.background[INFO].active.$description ||
+ 'The active background color of informational elements.',
+ value: {
+ _cerberusTheme: {
+ base: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.info.active.$value,
+ ).$value,
+ _lightMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.light.background.info.active.$value,
+ ).$value,
+ _darkMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.info.active.$value,
+ ).$value,
+ },
+ },
+ },
},
surface: {
initial: {
description:
+ semanticColors.surface[INFO].initial.$description ||
'The default color for a layout-based surface element (like a page or card) in a informational state.',
value: {
_cerberusTheme: {
@@ -96,6 +146,7 @@ export const infoTokens: InfoTokens = {
},
100: {
description:
+ semanticColors.surface[INFO]['100'].$description ||
'The second layer of color for static (surface) elements that display a info state - used on top of initial.',
value: {
_cerberusTheme: {
@@ -116,6 +167,7 @@ export const infoTokens: InfoTokens = {
},
200: {
description:
+ semanticColors.surface[INFO]['200'].$description ||
'The third layer of color for static (surface) elements that display a info state - used on top of 100.',
value: {
_cerberusTheme: {
@@ -138,7 +190,9 @@ export const infoTokens: InfoTokens = {
text: {
initial: {
- description: 'The default text color of informational elements.',
+ description:
+ semanticColors.text[INFO].initial.$description ||
+ 'The default text color of informational elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -157,7 +211,9 @@ export const infoTokens: InfoTokens = {
},
},
100: {
- description: 'The secondary text color of informational elements.',
+ description:
+ semanticColors.text[INFO]['100'].$description ||
+ 'The secondary text color of informational elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -176,7 +232,9 @@ export const infoTokens: InfoTokens = {
},
},
200: {
- description: 'The tertiary text color of informational elements.',
+ description:
+ semanticColors.text[INFO]['200'].$description ||
+ 'The tertiary text color of informational elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
diff --git a/packages/panda-preset/src/theme/semantic-tokens/warning.ts b/packages/panda-preset/src/theme/semantic-tokens/warning.ts
index 3f5ff889..2351d03c 100644
--- a/packages/panda-preset/src/theme/semantic-tokens/warning.ts
+++ b/packages/panda-preset/src/theme/semantic-tokens/warning.ts
@@ -1,5 +1,6 @@
import type { Prominence, SemanticToken } from './types'
-import { colors, deepGetByPaths, rawTokens } from '../../tokens'
+import { colors, deepGetByPaths, rawTokens, semanticColors } from '../../tokens'
+import { WARNING } from '../../recipes/shared/palettes'
/**
* This module is a collection of warning tokens that are used to generate the theme.
@@ -13,6 +14,11 @@ export interface WarningTokens {
readonly border: {
readonly initial: SemanticToken
}
+ readonly bg: {
+ readonly initial: SemanticToken
+ readonly hover: SemanticToken
+ readonly active: SemanticToken
+ }
readonly surface: {
readonly initial: SemanticToken
readonly 100: SemanticToken
@@ -28,7 +34,9 @@ export const warningTokens: WarningTokens = {
warning: {
border: {
initial: {
- description: 'The default border color of warning elements.',
+ description:
+ semanticColors.border[WARNING].initial.$description ||
+ 'The default border color of warning elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -48,9 +56,76 @@ export const warningTokens: WarningTokens = {
},
},
+ bg: {
+ initial: {
+ description:
+ semanticColors.background[WARNING].initial.$description ||
+ 'The default background color of warning elements.',
+ value: {
+ _cerberusTheme: {
+ base: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.initial.$value,
+ ).$value,
+ _lightMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.light.background.warning.initial.$value,
+ ).$value,
+ _darkMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.initial.$value,
+ ).$value,
+ },
+ },
+ },
+ hover: {
+ description:
+ semanticColors.background[WARNING].hover.$description ||
+ 'The hover background color of warning elements.',
+ value: {
+ _cerberusTheme: {
+ base: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.hover.$value,
+ ).$value,
+ _lightMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.light.background.warning.hover.$value,
+ ).$value,
+ _darkMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.hover.$value,
+ ).$value,
+ },
+ },
+ },
+ active: {
+ description:
+ semanticColors.background[WARNING].active.$description ||
+ 'The active background color of warning elements.',
+ value: {
+ _cerberusTheme: {
+ base: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.active.$value,
+ ).$value,
+ _lightMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.light.background.warning.active.$value,
+ ).$value,
+ _darkMode: deepGetByPaths(
+ colors,
+ rawTokens.semanticColors.dark.background.warning.active.$value,
+ ).$value,
+ },
+ },
+ },
+ },
+
surface: {
initial: {
description:
+ semanticColors.surface[WARNING].initial.$description ||
'The default color for static (surface) elements that display a warning state.',
value: {
_cerberusTheme: {
@@ -71,6 +146,7 @@ export const warningTokens: WarningTokens = {
},
100: {
description:
+ semanticColors.surface[WARNING]['100'].$description ||
'The second layer of color for static (surface) elements that display a warning state - used on top of initial.',
value: {
_cerberusTheme: {
@@ -91,6 +167,7 @@ export const warningTokens: WarningTokens = {
},
200: {
description:
+ semanticColors.surface[WARNING]['200'].$description ||
'The third layer of color for static (surface) elements that display a warning state - used on top of 100.',
value: {
_cerberusTheme: {
@@ -113,7 +190,9 @@ export const warningTokens: WarningTokens = {
text: {
initial: {
- description: 'The default text color of warning elements.',
+ description:
+ semanticColors.text[WARNING].initial.$description ||
+ 'The default text color of warning elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -132,7 +211,9 @@ export const warningTokens: WarningTokens = {
},
},
100: {
- description: 'The secondary text color of warning elements.',
+ description:
+ semanticColors.text[WARNING]['100'].$description ||
+ 'The secondary text color of warning elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -151,7 +232,9 @@ export const warningTokens: WarningTokens = {
},
},
200: {
- description: 'The tertiary text color of warning elements.',
+ description:
+ semanticColors.text[WARNING]['200'].$description ||
+ 'The tertiary text color of warning elements.',
value: {
_cerberusTheme: {
base: deepGetByPaths(
@@ -171,6 +254,7 @@ export const warningTokens: WarningTokens = {
},
inverse: {
description:
+ semanticColors.text[WARNING].inverse.$description ||
'The inverse version of the default text color of warning elements.',
value: {
_cerberusTheme: {
diff --git a/packages/panda-preset/src/tokens/semantic-colors.dark-mode.json b/packages/panda-preset/src/tokens/semantic-colors.dark-mode.json
index 3eb8c7e5..68068542 100644
--- a/packages/panda-preset/src/tokens/semantic-colors.dark-mode.json
+++ b/packages/panda-preset/src/tokens/semantic-colors.dark-mode.json
@@ -1103,6 +1103,44 @@
}
}
}
+ },
+ "warning": {
+ "initial": {
+ "$type": "color",
+ "$value": "colors.warning.70",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ },
+ "hover": {
+ "$type": "color",
+ "$value": "colors.warning.60",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ },
+ "active": {
+ "$type": "color",
+ "$value": "colors.warning.40",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ }
}
},
"ghost": {
@@ -1259,6 +1297,22 @@
}
}
},
+ "backdrop": {
+ "page": {
+ "initial": {
+ "$type": "color",
+ "$value": "#130024bf",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ }
+ }
+ },
"WIP-data-viz": {
"data-1": {
"$type": "color",
@@ -1309,22 +1363,6 @@
}
}
},
- "backdrop": {
- "page": {
- "initial": {
- "$type": "color",
- "$value": "#130024bf",
- "$description": "",
- "$extensions": {
- "com.figma": {
- "hiddenFromPublishing": false,
- "scopes": ["SHAPE_FILL"],
- "codeSyntax": {}
- }
- }
- }
- }
- },
"drop-shadow": {
"sm": {
"$type": "color",
diff --git a/packages/panda-preset/src/tokens/semantic-colors.light-mode.json b/packages/panda-preset/src/tokens/semantic-colors.light-mode.json
index 3525e23d..953a9644 100644
--- a/packages/panda-preset/src/tokens/semantic-colors.light-mode.json
+++ b/packages/panda-preset/src/tokens/semantic-colors.light-mode.json
@@ -1103,6 +1103,44 @@
}
}
}
+ },
+ "warning": {
+ "initial": {
+ "$type": "color",
+ "$value": "colors.warning.50",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ },
+ "hover": {
+ "$type": "color",
+ "$value": "colors.warning.60",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ },
+ "active": {
+ "$type": "color",
+ "$value": "colors.warning.70",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["FRAME_FILL", "SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ }
}
},
"ghost": {
@@ -1259,6 +1297,22 @@
}
}
},
+ "backdrop": {
+ "page": {
+ "initial": {
+ "$type": "color",
+ "$value": "#bcbaca80",
+ "$description": "",
+ "$extensions": {
+ "com.figma": {
+ "hiddenFromPublishing": false,
+ "scopes": ["SHAPE_FILL"],
+ "codeSyntax": {}
+ }
+ }
+ }
+ }
+ },
"WIP-data-viz": {
"data-1": {
"$type": "color",
@@ -1309,22 +1363,6 @@
}
}
},
- "backdrop": {
- "page": {
- "initial": {
- "$type": "color",
- "$value": "#bcbaca80",
- "$description": "",
- "$extensions": {
- "com.figma": {
- "hiddenFromPublishing": false,
- "scopes": ["SHAPE_FILL"],
- "codeSyntax": {}
- }
- }
- }
- }
- },
"drop-shadow": {
"sm": {
"$type": "color",
diff --git a/packages/react/src/components/Notification.tsx b/packages/react/src/components/Notification.tsx
index 407ed40c..f871e0f2 100644
--- a/packages/react/src/components/Notification.tsx
+++ b/packages/react/src/components/Notification.tsx
@@ -12,7 +12,6 @@ import {
type PropsWithChildren,
type MouseEvent,
} from 'react'
-import { IconButton } from './IconButton'
import { Close } from '@cerberus/icons'
import { $cerberusIcons } from '../config/defineIcons'
import type { IconType } from '../config/cerbIcons'
@@ -86,9 +85,14 @@ export function Notification(props: PropsWithChildren) {
{children}
-
+
+
)
}
diff --git a/packages/react/src/context/notification-center.tsx b/packages/react/src/context/notification-center.tsx
index bb0ecfd4..333a81ad 100644
--- a/packages/react/src/context/notification-center.tsx
+++ b/packages/react/src/context/notification-center.tsx
@@ -14,10 +14,11 @@ import { Show } from '../components/Show'
import { NotificationHeading } from '../components/NotificationHeading'
import { NotificationDescription } from '../components/NotificationDescription'
import { Notification } from '../components/Notification'
-import { vstack } from '@cerberus-design/styled-system/patterns'
+import { animateIn, vstack } from '@cerberus-design/styled-system/patterns'
import { Portal, type PortalProps } from '../components/Portal'
-import { cx } from '@cerberus-design/styled-system/css'
import { notification } from '@cerberus-design/styled-system/recipes'
+import { Button } from '../components/Button'
+import { cx } from '@cerberus-design/styled-system/css'
/**
* This module provides a context and hook for notifications.
@@ -67,6 +68,7 @@ export function NotificationCenter(
const [activeNotifications, setActiveNotifications] = useState<
NotifyOptions[]
>([])
+ const styles = notification()
const handleNotify = useCallback((options: NotifyOptions) => {
setActiveNotifications((prev) => {
@@ -84,6 +86,15 @@ export function NotificationCenter(
})
}, [])
+ const handleCloseAll = useCallback(() => {
+ setActiveNotifications((prev) => {
+ prev.forEach((item) => {
+ if (item.onClose) item.onClose()
+ })
+ return []
+ })
+ }, [])
+
const value = useMemo(
() => ({
notify: handleNotify,
@@ -100,34 +111,45 @@ export function NotificationCenter(
0}>
-
+
= 4}>
+
+
+
- {activeNotifications.map((option) => (
-
-
- {option.heading}
-
-
- {option.description}
-
-
- ))}
+ })}
+ style={{
+ alignItems: 'flex-end',
+ }}
+ >
+ {activeNotifications.map((option) => (
+
+
+ {option.heading}
+
+
+ {option.description}
+
+
+ ))}
+
diff --git a/tests/panda-preset/recipes/slots/notification.test.ts b/tests/panda-preset/recipes/slots/notification.test.ts
index 71265a7d..cbd08c54 100644
--- a/tests/panda-preset/recipes/slots/notification.test.ts
+++ b/tests/panda-preset/recipes/slots/notification.test.ts
@@ -10,9 +10,11 @@ describe('notification recipe', () => {
test('should have a center style', () => {
expect(notification.base?.center).toMatchObject({
+ color: 'colorPalette.text.initial',
position: 'fixed',
right: '4',
- top: '4',
+ textAlign: 'right',
+ top: '24',
zIndex: 'toast',
})
})
@@ -20,6 +22,7 @@ describe('notification recipe', () => {
test('should have a base style', () => {
expect(notification.base?.dialog).toMatchObject({
bgColor: 'colorPalette.surface.initial',
+ color: 'colorPalette.text.initial',
maxW: '29rem',
minH: '3.125rem',
opacity: '0',
@@ -46,7 +49,7 @@ describe('notification recipe', () => {
test('should have a heading style', () => {
expect(notification.base?.heading).toMatchObject({
- color: 'colorPalette.text.initial',
+ color: 'inherit',
textStyle: 'label-md',
fontWeight: '600',
userSelect: 'none',
@@ -55,7 +58,7 @@ describe('notification recipe', () => {
test('should have a description style', () => {
expect(notification.base?.description).toMatchObject({
- color: 'colorPalette.text.initial',
+ color: 'inherit',
textStyle: 'body-sm',
userSelect: 'none',
['& :is(a)']: {
@@ -65,6 +68,28 @@ describe('notification recipe', () => {
})
})
+ test('should have a close style', () => {
+ expect(notification.base?.close).toMatchObject({
+ bgColor: 'transparent',
+ color: 'inherit',
+ _hover: {
+ bgColor: 'colorPalette.bg.hover',
+ },
+ })
+ })
+
+ test('should have a close all style', () => {
+ expect(notification.base?.closeAll).toMatchObject({
+ bgColor: 'transparent',
+ color: 'action.text.inverse',
+ pxi: '0',
+ _hover: {
+ bgColor: 'transparent',
+ color: 'action.bg.hover',
+ },
+ })
+ })
+
test('should had a default variant', () => {
expect(notification.defaultVariants).toMatchObject({
palette: 'info',
diff --git a/tests/panda-preset/theme/semantic-tokens/info.test.ts b/tests/panda-preset/theme/semantic-tokens/info.test.ts
index 6ad5b6b8..e40464c8 100644
--- a/tests/panda-preset/theme/semantic-tokens/info.test.ts
+++ b/tests/panda-preset/theme/semantic-tokens/info.test.ts
@@ -46,6 +46,30 @@ describe('infoTokens', () => {
).toEqual('#9ACFEE')
})
+ test('should have a bg.hover property', () => {
+ expect(
+ formatToken(infoTokens.info.bg.hover.value._cerberusTheme.base),
+ ).toEqual('#013655')
+ expect(
+ formatToken(infoTokens.info.bg.hover.value._cerberusTheme._darkMode),
+ ).toEqual('#013655')
+ expect(
+ formatToken(infoTokens.info.bg.hover.value._cerberusTheme._lightMode),
+ ).toEqual('#CCE7F7')
+ })
+
+ test('should have a bg.active property', () => {
+ expect(
+ formatToken(infoTokens.info.bg.active.value._cerberusTheme.base),
+ ).toEqual('#35A0DD')
+ expect(
+ formatToken(infoTokens.info.bg.active.value._cerberusTheme._darkMode),
+ ).toEqual('#35A0DD')
+ expect(
+ formatToken(infoTokens.info.bg.active.value._cerberusTheme._lightMode),
+ ).toEqual('#35A0DD')
+ })
+
test('should have a surface.initial property', () => {
expect(infoTokens.info.surface).toBeDefined()
})
diff --git a/tests/panda-preset/theme/semantic-tokens/warning.test.ts b/tests/panda-preset/theme/semantic-tokens/warning.test.ts
index 3065b099..7bb92941 100644
--- a/tests/panda-preset/theme/semantic-tokens/warning.test.ts
+++ b/tests/panda-preset/theme/semantic-tokens/warning.test.ts
@@ -28,6 +28,54 @@ describe('warning', () => {
).toEqual('#F4DA49')
})
+ test('should have a bg.initial property', () => {
+ expect(
+ formatToken(warningTokens.warning.bg.initial.value._cerberusTheme.base),
+ ).toEqual('#C1A716')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.initial.value._cerberusTheme._darkMode,
+ ),
+ ).toEqual('#C1A716')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.initial.value._cerberusTheme._lightMode,
+ ),
+ ).toEqual('#F4DA49')
+ })
+
+ test('should have a bg.hover property', () => {
+ expect(
+ formatToken(warningTokens.warning.bg.hover.value._cerberusTheme.base),
+ ).toEqual('#F1D11B')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.hover.value._cerberusTheme._darkMode,
+ ),
+ ).toEqual('#F1D11B')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.hover.value._cerberusTheme._lightMode,
+ ),
+ ).toEqual('#F1D11B')
+ })
+
+ test('should have a bg.active property', () => {
+ expect(
+ formatToken(warningTokens.warning.bg.active.value._cerberusTheme.base),
+ ).toEqual('#F7E376')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.active.value._cerberusTheme._darkMode,
+ ),
+ ).toEqual('#F7E376')
+ expect(
+ formatToken(
+ warningTokens.warning.bg.active.value._cerberusTheme._lightMode,
+ ),
+ ).toEqual('#C1A716')
+ })
+
test('should have a surface.initial property', () => {
expect(
formatToken(