diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6182408e57..e61cae99e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1456,6 +1456,9 @@ importers: '@semcore/icon': specifier: workspace:* version: link:../icon + '@semcore/illustration': + specifier: workspace:* + version: link:../illustration '@semcore/testing-utils': specifier: workspace:* version: link:../../tools/testing-utils diff --git a/semcore/notice/package.json b/semcore/notice/package.json index 574c84dc20..6ef6607d69 100644 --- a/semcore/notice/package.json +++ b/semcore/notice/package.json @@ -33,6 +33,7 @@ "@semcore/core": "workspace:*", "@semcore/base-components": "workspace:*", "@semcore/icon": "workspace:*", + "@semcore/illustration": "workspace:*", "@semcore/testing-utils": "workspace:*" } } diff --git a/semcore/notice/src/Notice.tsx b/semcore/notice/src/Notice.tsx index b685d31d5d..f12d567db5 100644 --- a/semcore/notice/src/Notice.tsx +++ b/semcore/notice/src/Notice.tsx @@ -93,7 +93,9 @@ class RootNotice extends Component< render() { const SNotice = Root; - const { Children, styles, hidden, theme, resolveColor, getI18nText } = this.asProps; + const SIcon = Box; + const SIllustration = Box; + const { Children, styles, hidden, theme, resolveColor, getI18nText, icon, illustration } = this.asProps; const color = resolveColor(theme); const useTheme = isCustomTheme(theme) ? 'custom' : theme; @@ -115,6 +117,11 @@ class RootNotice extends Component< aria-label={ariaLabel} ref={this.ref} > + {icon !== undefined && ( + // @ts-expect-error we use theme in css-only + {icon} + )} + {illustration !== undefined && ({illustration})} , ); diff --git a/semcore/notice/src/Notice.type.ts b/semcore/notice/src/Notice.type.ts index 8b300dab63..3f5961b9b9 100644 --- a/semcore/notice/src/Notice.type.ts +++ b/semcore/notice/src/Notice.type.ts @@ -1,7 +1,9 @@ import type { NSAnimation, NSBox } from '@semcore/base-components'; import type { NSButton } from '@semcore/button'; import type { PropGetterFn, Intergalactic } from '@semcore/core'; -import type { Text } from '@semcore/typography'; +import type Icon from '@semcore/icon'; +import type { IllustrationProps } from '@semcore/illustration'; +import type { NSText } from '@semcore/typography'; import type { LocalizedMessaged } from './translations/__intergalactic-dynamic-locales'; @@ -22,7 +24,11 @@ declare namespace NSNotice { duration?: number; /** Specifies the locale for i18n support */ locale?: string; - }; + } & ({ + icon?: typeof Icon; + } | { + illustration?: React.ElementType; + }); type DefaultProps = { theme: 'info'; i18n: LocalizedMessaged; @@ -49,11 +55,11 @@ declare namespace NSNotice { } namespace Title { - type Component = typeof Text; + type Component = NSText.Component; } namespace Text { - type Component = typeof Text; + type Component = NSText.Component; } namespace Close { @@ -61,6 +67,9 @@ declare namespace NSNotice { } type Component = Intergalactic.Component<'div', Props, Ctx> & { + /** + * @deprecated. Use icon or illustration props instead. + */ Label: Label.Component; Actions: Actions.Component; Content: Content.Component; diff --git a/semcore/notice/src/NoticeSmart.tsx b/semcore/notice/src/NoticeSmart.tsx index 854db2ce82..4586ed0cb2 100644 --- a/semcore/notice/src/NoticeSmart.tsx +++ b/semcore/notice/src/NoticeSmart.tsx @@ -1,10 +1,12 @@ +import { Box } from '@semcore/base-components'; import type { Intergalactic } from '@semcore/core'; -import { createComponent, Component, Root } from '@semcore/core'; +import { sstyled, createComponent, Component, Root } from '@semcore/core'; import isNode from '@semcore/core/lib/utils/isNode'; import React from 'react'; import Notice from './Notice'; import type { NSNoticeSmart } from './NoticeSmart.type'; +import style from './style/notice.shadow.css'; class NoticeSmart extends Component< Intergalactic.InternalTypings.InferComponentProps, @@ -15,17 +17,21 @@ class NoticeSmart extends Component< NSNoticeSmart.DefaultProps > { static displayName = 'NoticeSmart'; - + static style = style; static defaultProps = { theme: 'info', } as const; render() { const SNoticeSmart = Root; - const { label, title, actions, closable, onClose, text } = this.asProps; + const SIcon = Box; + const SIllustration = Box; + const { label, title, actions, closable, onClose, text, icon, illustration, styles, theme } = this.asProps; - return ( + return sstyled(styles)( + {icon !== undefined && ({icon})} + {illustration !== undefined && ({illustration})} {isNode(label) && {label}} {isNode(title) && {title}} @@ -33,7 +39,7 @@ class NoticeSmart extends Component< {isNode(actions) && {actions}} {closable && } - + , ); } } diff --git a/semcore/notice/src/NoticeSmart.type.ts b/semcore/notice/src/NoticeSmart.type.ts index 47207575b6..d8312c0857 100644 --- a/semcore/notice/src/NoticeSmart.type.ts +++ b/semcore/notice/src/NoticeSmart.type.ts @@ -1,11 +1,15 @@ import type { Intergalactic } from '@semcore/core'; +import type Icon from '@semcore/icon'; +import type { IllustrationProps } from '@semcore/illustration'; import type { NSNotice } from './Notice.type'; declare namespace NSNoticeSmart { - type Props = NSNotice.Props & { + type Props = Omit & { /** * A custom element for additional information + * + * @deprecated. Use icon or illustration props instead. */ label?: React.ReactNode; @@ -29,7 +33,13 @@ declare namespace NSNoticeSmart { * Callback on a click on the close button */ onClose?: (event: React.SyntheticEvent) => void; - }; + } & ({ + icon?: typeof Icon; + illustration?: never; + } | { + icon?: never; + illustration?: React.ElementType; + }); type DefaultProps = { theme: 'info'; }; diff --git a/semcore/notice/src/style/notice.shadow.css b/semcore/notice/src/style/notice.shadow.css index d905d6496e..70558d58b8 100644 --- a/semcore/notice/src/style/notice.shadow.css +++ b/semcore/notice/src/style/notice.shadow.css @@ -1,6 +1,6 @@ SNotice { display: flex; - padding: var(--intergalactic-spacing-4x, 16px); + padding: var(--intergalactic-spacing-content-padding-large, 16px); font-size: var(--intergalactic-fs-200, 14px); line-height: var(--intergalactic-lh-200, 142%); box-sizing: border-box; @@ -8,6 +8,7 @@ SNotice { border-width: 1px; border-radius: var(--intergalactic-surface-rounded, 8px); color: var(--intergalactic-text-primary, oklch(0.1 0.03 137 / 0.899)); + gap: var(--intergalactic-spacing-content-gap-large, 8px); } SNotice[theme='info'] { @@ -82,44 +83,59 @@ SContent { SActions { flex-shrink: 0; - margin-top: var(--intergalactic-spacing-3x, 12px); + display: flex; + gap: var(--intergalactic-spacing-content-gap-large, 8px); + margin-top: var(--intergalactic-spacing-content-padding-small, 8px); } SLabel { - min-height: var(--intergalactic-form-control-m, 32px); height: fit-content; - margin-right: var(--intergalactic-spacing-2x, 8px); display: inline-flex; align-items: center; + margin-top: 6px; +} + +SIcon { + height: fit-content; + display: inline-flex; + align-items: center; + margin-top: 6px; +} + +SIllustration { + height: fit-content; + display: inline-flex; + align-items: center; + margin-right: var(--intergalactic-spacing-content-padding-xlarge, 20px); } -SLabel[theme='info'] { +SLabel[theme='info'], SIcon[theme='info'] { color: var(--intergalactic-icon-primary-neutral, oklch(0.092 0.024 152.2 / 0.526)); } -SLabel[theme='danger'] { +SLabel[theme='danger'], SIcon[theme='danger'] { color: var(--intergalactic-icon-primary-critical, oklch(0.552 0.226 28.7 / 0.848)); } -SLabel[theme='warning'] { +SLabel[theme='warning'], SIcon[theme='warning'] { color: var(--intergalactic-icon-primary-warning, oklch(0.728 0.188 51.8)); } -SLabel[theme='success'] { +SLabel[theme='success'], SIcon[theme='success'] { color: var(--intergalactic-icon-primary-success, oklch(0.595 0.124 165.4)); } -SLabel[theme='muted'] { +SLabel[theme='muted'], SIcon[theme='muted'] { color: var(--intergalactic-icon-primary-neutral, oklch(0.092 0.024 152.2 / 0.526)); } -SLabel[theme='custom'] { +SLabel[theme='custom'], SIcon[theme='custom'] { color: var(--color); } SCloseIcon { flex-shrink: 0; - margin-left: var(--intergalactic-spacing-4x, 16px); + margin-left: var(--intergalactic-spacing-content-padding-large, 16px); } SNotice[theme='custom'] { @@ -128,11 +144,10 @@ SNotice[theme='custom'] { } STitle { - margin-top: var(--intergalactic-spacing-05x, 2px); - margin-bottom: var(--intergalactic-spacing-05x, 2px); + margin-top: calc(var(--intergalactic-spacing-content-padding-xsmall, 4px) / 2); } SText { - margin-top: var(--intergalactic-spacing-1x, 4px); - margin-bottom: var(--intergalactic-spacing-1x, 4px); + margin-top: var(--intergalactic-spacing-content-padding-xsmall, 4px); + margin-bottom: var(--intergalactic-spacing-content-padding-xsmall, 4px); } diff --git a/stories/components/notice/docs/examples/basic_notice.tsx b/stories/components/notice/docs/examples/basic_notice.tsx index 354d9fa51f..97c1ae69b7 100644 --- a/stories/components/notice/docs/examples/basic_notice.tsx +++ b/stories/components/notice/docs/examples/basic_notice.tsx @@ -7,12 +7,8 @@ import Notice from '@semcore/ui/notice'; import React from 'react'; const Demo = () => ( - - - - - - + + }> New keyboard shortcuts are available @@ -22,7 +18,7 @@ const Demo = () => ( - @@ -31,11 +27,7 @@ const Demo = () => ( - - - - - + }> Data export is in progress @@ -45,7 +37,7 @@ const Demo = () => ( - @@ -54,11 +46,7 @@ const Demo = () => ( - - - - - + }> Payment method expires soon @@ -68,7 +56,7 @@ const Demo = () => ( - @@ -77,11 +65,7 @@ const Demo = () => ( - - - - - + }> API request limit reached @@ -91,7 +75,7 @@ const Demo = () => ( - @@ -100,11 +84,7 @@ const Demo = () => ( - - - - - + }> Backup completed successfully @@ -114,7 +94,7 @@ const Demo = () => ( - diff --git a/stories/components/notice/docs/examples/custom_notice.tsx b/stories/components/notice/docs/examples/custom_notice.tsx index ca9289efc6..4bc6f7bc7b 100644 --- a/stories/components/notice/docs/examples/custom_notice.tsx +++ b/stories/components/notice/docs/examples/custom_notice.tsx @@ -4,10 +4,7 @@ import Notice, { type NSNotice } from '@semcore/ui/notice'; import React from 'react'; const Demo = (props: NSNotice.Props) => ( - - - - + }> Strategize your next move with daily and weekly traffic data diff --git a/stories/components/notice/docs/examples/noticesmart.tsx b/stories/components/notice/docs/examples/noticesmart.tsx index 6083037a03..1ce15e3dc8 100644 --- a/stories/components/notice/docs/examples/noticesmart.tsx +++ b/stories/components/notice/docs/examples/noticesmart.tsx @@ -13,7 +13,7 @@ const Demo = () => { return ( } + icon={} aria-label='New tool announcement' closable onClose={() => setFirstHidden(true)} @@ -25,7 +25,7 @@ const Demo = () => { } + icon={} title="We've released a cool new feature!" closable onClose={() => setSecondHidden(true)} @@ -40,7 +40,7 @@ const Demo = () => { } + icon={} aria-label='Maintenance notice' text='Starting new campaigns is temporarily unavailable, but you can continue working with your existing Link Building campaigns.' /> diff --git a/stories/components/notice/tests/Notice.stories.tsx b/stories/components/notice/tests/Notice.stories.tsx index aff2592fa3..027d7f109a 100644 --- a/stories/components/notice/tests/Notice.stories.tsx +++ b/stories/components/notice/tests/Notice.stories.tsx @@ -2,7 +2,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import NoticeBigIllustrationExample from './examples/notice_big_illustration'; import NoticeMediumIllustrationExample from './examples/notice_medium_illustration'; -import NoticeSmallIllustrationExample from './examples/notice_small_illustration'; import NoticeStatesExample from './examples/notice_with_different_states'; const meta: Meta = { @@ -14,10 +13,6 @@ export const NoticeMediumIllustration: StoryObj = { render: NoticeMediumIllustrationExample, }; -export const NoticeSmallIllustration: StoryObj = { - render: NoticeSmallIllustrationExample, -}; - export const NoticeBigIllustration: StoryObj = { render: NoticeBigIllustrationExample, }; diff --git a/stories/components/notice/tests/examples/notice_big_illustration.tsx b/stories/components/notice/tests/examples/notice_big_illustration.tsx index efbd292aa9..0c048b1ebe 100644 --- a/stories/components/notice/tests/examples/notice_big_illustration.tsx +++ b/stories/components/notice/tests/examples/notice_big_illustration.tsx @@ -6,12 +6,8 @@ import Notice from '@semcore/ui/notice'; import React from 'react'; const Demo = () => ( - - - - - - + + }> Your subscription has expired @@ -21,7 +17,7 @@ const Demo = () => ( - @@ -30,11 +26,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -44,7 +36,7 @@ const Demo = () => ( - @@ -53,11 +45,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -70,7 +58,7 @@ const Demo = () => ( - @@ -79,11 +67,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -96,7 +80,7 @@ const Demo = () => ( - @@ -105,11 +89,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -119,7 +99,7 @@ const Demo = () => ( - diff --git a/stories/components/notice/tests/examples/notice_medium_illustration.tsx b/stories/components/notice/tests/examples/notice_medium_illustration.tsx index b89a6ea303..ee023a3d05 100644 --- a/stories/components/notice/tests/examples/notice_medium_illustration.tsx +++ b/stories/components/notice/tests/examples/notice_medium_illustration.tsx @@ -6,12 +6,8 @@ import Notice from '@semcore/ui/notice'; import React from 'react'; const Demo = () => ( - - - - - - + + }> Your subscription has expired @@ -21,7 +17,7 @@ const Demo = () => ( - @@ -30,11 +26,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -44,7 +36,7 @@ const Demo = () => ( - @@ -53,11 +45,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -70,7 +58,7 @@ const Demo = () => ( - @@ -79,11 +67,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -96,7 +80,7 @@ const Demo = () => ( - @@ -105,11 +89,7 @@ const Demo = () => ( - - - - - + }> Your subscription has expired @@ -119,7 +99,7 @@ const Demo = () => ( - diff --git a/stories/components/notice/tests/examples/notice_small_illustration.tsx b/stories/components/notice/tests/examples/notice_small_illustration.tsx deleted file mode 100644 index b0f651b951..0000000000 --- a/stories/components/notice/tests/examples/notice_small_illustration.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import Coffee from '@semcore/illustration/Coffee'; -import MailSent from '@semcore/illustration/MailSent'; -import { Flex } from '@semcore/ui/base-components'; -import Button from '@semcore/ui/button'; -import Notice from '@semcore/ui/notice'; -import React from 'react'; - -const Demo = () => ( - - - - - - - - Your subscription has expired - - - 49 out of your 50 projects are now locked. They will be deleted in 7 days (on August 22). - To unlock your projects, please upgrade your subscription. - - - - - - - - - - - - - - - - - Your subscription has expired - - - 49 out of your 50 projects are now locked. They will be deleted in 7 days (on August 22). - To unlock your projects, please upgrade your subscription. - - - - - - - - - - - - - - - - - Your subscription has expired - - - 49 out of your 50 projects are now locked. They will be deleted in 7 days (on August 22). - To unlock your projects, please upgrade your subscription.Please tell us how to improve - something. 49 out of your Star Wars: The Force Awakens shattered box office records upon - its debut becoming the biggest film of all time in. The reports are based on the data from - the Russian Federation and the CIS. - - - - - - - - - - - - - - - - - Your subscription has expired - - - 49 out of your 50 projects are now locked. They will be deleted in 7 days (on August 22). - To unlock your projects, please upgrade your subscription.Please tell us how to improve - something. 49 out of your Star Wars: The Force Awakens shattered box office records upon - its debut becoming the biggest film of all time in. The reports are based on the data from - the Russian Federation and the CIS. - - - - - - - - - - - - - - - - - Your subscription has expired - - - 49 out of your 50 projects are now locked. They will be deleted in 7 days (on August 22). - To unlock your projects, please upgrade your subscription. - - - - - - - - - - -); - -export default Demo; diff --git a/stories/components/notice/tests/examples/notice_with_different_states.tsx b/stories/components/notice/tests/examples/notice_with_different_states.tsx index dce555e50e..521df8a257 100644 --- a/stories/components/notice/tests/examples/notice_with_different_states.tsx +++ b/stories/components/notice/tests/examples/notice_with_different_states.tsx @@ -20,15 +20,12 @@ const NoticeSmokeDemo = () => { {/* 2. Full Featured Notice */} - - - - + }> Success! Everything worked just fine. - + @@ -44,10 +41,7 @@ const NoticeSmokeDemo = () => { {/* 4. Icon + Text only */} - - - - + }> Something went wrong. diff --git a/website/docs/style/design-tokens/design-tokens.json b/website/docs/style/design-tokens/design-tokens.json index 3d4cec6315..688e63d500 100644 --- a/website/docs/style/design-tokens/design-tokens.json +++ b/website/docs/style/design-tokens/design-tokens.json @@ -3201,7 +3201,6 @@ "color-picker", "input", "input-tags", - "notice", "pills", "tab-line", "time-picker" @@ -3240,6 +3239,7 @@ "counter", "dropdown", "dropdown-menu", + "notice", "pills" ] }, @@ -3260,6 +3260,7 @@ "base-components", "dropdown", "modal", + "notice", "pills" ] }, @@ -3284,7 +3285,8 @@ "value": "16px", "description": "Large padding for content inside controls and surfaces.", "components": [ - "feature-popover" + "feature-popover", + "notice" ] }, { @@ -3292,7 +3294,8 @@ "value": "20px", "description": "Extra large padding for content inside controls and surfaces.", "components": [ - "card" + "card", + "notice" ] }, { @@ -3344,6 +3347,7 @@ "button", "checkbox", "dropdown", + "notice", "radio", "select" ]