diff --git a/system/core/src/components/FormBanner.ts b/system/core/src/components/FormBanner.ts
new file mode 100644
index 000000000..9267e21a1
--- /dev/null
+++ b/system/core/src/components/FormBanner.ts
@@ -0,0 +1,56 @@
+import { css } from '../utils';
+
+export const element = 'div';
+export const className = 'form-banner';
+
+const variants = [
+ 'success',
+ 'info',
+ 'error',
+ 'warning',
+ 'neutral',
+ 'purple',
+ 'orange'
+] as const;
+
+export type FormBannerVariant = (typeof variants)[number];
+
+export interface Props {
+ 'data-variant': FormBannerVariant;
+}
+
+export const fullStyles = css`
+ display: flex;
+ gap: var(--spacing-l2);
+ color: var(--neutral-text);
+ background: var(--neutral-surface);
+ border-radius: var(--border-radius-small);
+ padding: var(--spacing-l4) var(--spacing-l3);
+ align-items: flex-start;
+ width: 100%;
+
+ &[data-variant='error'] {
+ color: var(--error-text);
+ background: var(--error-surface);
+ }
+ &[data-variant='warning'] {
+ color: var(--warning-text);
+ background: var(--warning-surface);
+ }
+ &[data-variant='success'] {
+ color: var(--success-text);
+ background: var(--success-surface);
+ }
+ &[data-variant='info'] {
+ color: var(--info-text);
+ background: var(--info-surface);
+ }
+ &[data-variant='purple'] {
+ color: var(--purple-text);
+ background: var(--purple-surface);
+ }
+ &[data-variant='orange'] {
+ color: var(--orange-text);
+ background: var(--orange-surface);
+ }
+`;
diff --git a/system/core/src/index.ts b/system/core/src/index.ts
index 26c7b5d1d..422dddabc 100644
--- a/system/core/src/index.ts
+++ b/system/core/src/index.ts
@@ -13,6 +13,7 @@ export * as checkboxRadioLabel from './components/CheckboxRadioLabel';
export * as childAnchors from './components/ChildAnchors';
export * as chip from './components/Chip';
export * as chipRow from './components/ChipRow';
+export * as formBanner from './components/FormBanner';
export * as iconButton from './components/IconButton';
export * as inputAlert from './components/InputAlert';
export * as inputCore from './components/InputCore';
diff --git a/system/react-css/src/config.tsx b/system/react-css/src/config.tsx
index 52adb074c..dd7071eed 100644
--- a/system/react-css/src/config.tsx
+++ b/system/react-css/src/config.tsx
@@ -39,7 +39,7 @@ export function configureDefaults(defaults: CoreConfigDefaults): void {
}
export function getSentimentIcon(
- variant: 'success' | 'error' | 'neutral' | 'info' | 'warning',
+ variant: 'success' | 'error' | 'neutral' | 'info' | 'warning' | 'default',
size = getConfigDefault('iconSize')
): JSX.Element {
switch (variant) {
@@ -47,10 +47,11 @@ export function getSentimentIcon(
return ;
case 'error':
return ;
+ case 'warning':
+ return ;
case 'neutral':
case 'info':
+ case 'default':
return ;
- case 'warning':
- return ;
}
}
diff --git a/system/react-css/src/index.ts b/system/react-css/src/index.ts
index 660260cf3..5b74c8f90 100644
--- a/system/react-css/src/index.ts
+++ b/system/react-css/src/index.ts
@@ -75,6 +75,13 @@ export {
export type { Props as CheckboxRadioLabelProps } from './structuredComponents/CheckboxRadioLabel';
export { Chip } from './structuredComponents/Chip';
export type { Props as ChipProps } from './structuredComponents/Chip';
+export {
+ FormBannerCore,
+ FormBannerMessage,
+ FormBannerIconWrapper,
+ FormBanner
+} from './structuredComponents/FormBanner';
+export type { Props as FormBannerProps } from './structuredComponents/FormBanner';
export { Input } from './structuredComponents/Input';
export type { Props as InputProps } from './structuredComponents/Input';
export { InputAlert } from './structuredComponents/InputAlert';
diff --git a/system/react-css/src/structuredComponents/FormBanner.tsx b/system/react-css/src/structuredComponents/FormBanner.tsx
new file mode 100644
index 000000000..3e228498d
--- /dev/null
+++ b/system/react-css/src/structuredComponents/FormBanner.tsx
@@ -0,0 +1,69 @@
+import type { formBanner } from '@tablecheck/tablekit-core';
+import * as React from 'react';
+
+import { getSentimentIcon } from '../config';
+
+export type Props = formBanner.Props;
+
+export const FormBannerCore = React.forwardRef<
+ HTMLDivElement,
+ Props & React.HTMLAttributes
+>((props, ref) => (
+
+));
+
+export const FormBannerMessage = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>((props, ref) => (
+
+));
+
+export const FormBannerIconWrapper = React.forwardRef<
+ HTMLSpanElement,
+ React.HTMLAttributes
+>((props, ref) => (
+
+));
+
+interface ComposedProps extends Props {
+ /**
+ * Icon to display in the form banner. Pass `null` to display sentiment one.
+ */
+ icon?: React.ReactNode;
+ children: React.ReactNode;
+}
+
+function getIcon(variant: Props['data-variant']): JSX.Element {
+ if (variant === 'purple' || variant === 'orange')
+ return getSentimentIcon('default');
+ return getSentimentIcon(variant);
+}
+
+export const FormBanner = React.forwardRef<
+ HTMLDivElement,
+ ComposedProps & React.HTMLAttributes
+>((props, ref) => {
+ const { icon, title, children, ...passThrough } = props;
+ return (
+
+
+ {icon ?? getIcon(passThrough['data-variant'])}
+
+ {children}
+
+ );
+});
diff --git a/system/react/src/config.tsx b/system/react/src/config.tsx
index 52adb074c..dd7071eed 100644
--- a/system/react/src/config.tsx
+++ b/system/react/src/config.tsx
@@ -39,7 +39,7 @@ export function configureDefaults(defaults: CoreConfigDefaults): void {
}
export function getSentimentIcon(
- variant: 'success' | 'error' | 'neutral' | 'info' | 'warning',
+ variant: 'success' | 'error' | 'neutral' | 'info' | 'warning' | 'default',
size = getConfigDefault('iconSize')
): JSX.Element {
switch (variant) {
@@ -47,10 +47,11 @@ export function getSentimentIcon(
return ;
case 'error':
return ;
+ case 'warning':
+ return ;
case 'neutral':
case 'info':
+ case 'default':
return ;
- case 'warning':
- return ;
}
}
diff --git a/system/react/src/index.ts b/system/react/src/index.ts
index 1d4025ef6..85f72311c 100644
--- a/system/react/src/index.ts
+++ b/system/react/src/index.ts
@@ -140,6 +140,13 @@ export {
export type { Props as AlertProps } from './structuredComponents/Alert';
export { chipStyledComponents, Chip } from './structuredComponents/Chip';
export type { Props as ChipProps } from './structuredComponents/Chip';
+export {
+ FormBannerCore,
+ FormBannerMessage,
+ FormBannerIconWrapper,
+ FormBanner
+} from './structuredComponents/FormBanner';
+export type { Props as FormBannerProps } from './structuredComponents/FormBanner';
export { Input } from './structuredComponents/Input';
export type { Props as InputProps } from './structuredComponents/Input';
export { InputAlertInner, InputAlert } from './structuredComponents/InputAlert';
diff --git a/system/react/src/structuredComponents/FormBanner.tsx b/system/react/src/structuredComponents/FormBanner.tsx
new file mode 100644
index 000000000..2041b4ebd
--- /dev/null
+++ b/system/react/src/structuredComponents/FormBanner.tsx
@@ -0,0 +1,56 @@
+import styled from '@emotion/styled';
+import { formBanner } from '@tablecheck/tablekit-core';
+import * as React from 'react';
+
+import { getSentimentIcon } from '../config';
+
+export type Props = formBanner.Props;
+
+export const FormBannerCore = styled.div`
+ ${formBanner.fullStyles}
+`;
+
+export const FormBannerMessage = styled.div`
+ font: var(--body-2);
+`;
+
+export const FormBannerIconWrapper = React.forwardRef<
+ HTMLSpanElement,
+ React.HTMLAttributes
+>((props, ref) => (
+
+));
+
+interface ComposedProps extends Props {
+ /**
+ * Icon to display in the form banner. Pass `null` to display sentiment one.
+ */
+ icon?: React.ReactNode;
+ children: React.ReactNode;
+}
+
+function getIcon(variant: Props['data-variant']): JSX.Element {
+ if (variant === 'purple' || variant === 'orange')
+ return getSentimentIcon('default');
+ return getSentimentIcon(variant);
+}
+
+export const FormBanner = React.forwardRef<
+ HTMLDivElement,
+ ComposedProps & React.HTMLAttributes
+>((props, ref) => {
+ const { icon, children, ...passThrough } = props;
+ return (
+
+
+ {icon ?? getIcon(passThrough['data-variant'])}
+
+ {children}
+
+ );
+});
diff --git a/system/stories/src/FormBanner.stories.tsx b/system/stories/src/FormBanner.stories.tsx
new file mode 100644
index 000000000..17e928df9
--- /dev/null
+++ b/system/stories/src/FormBanner.stories.tsx
@@ -0,0 +1,52 @@
+import { Meta, StoryFn } from '@storybook/react';
+import { formBanner } from '@tablecheck/tablekit-core';
+import * as emotion from '@tablecheck/tablekit-react';
+import * as css from '@tablecheck/tablekit-react-css';
+import * as React from 'react';
+
+const contentVariants: emotion.FormBannerProps['data-variant'][] = [
+ 'success',
+ 'info',
+ 'error',
+ 'warning',
+ 'neutral',
+ 'purple',
+ 'orange'
+];
+
+type LayoutComponents = Record<'FormBanner', React.ElementType>;
+
+export default {
+ title: 'Components/FormBanner',
+ component: emotion.FormBanner,
+ parameters: {
+ ...formBanner,
+ variants: contentVariants,
+ auxiliaryComponents: [
+ emotion.FormBannerIconWrapper,
+ emotion.FormBannerMessage
+ ]
+ }
+} as Meta;
+
+const Template: StoryFn = ({ FormBanner }) => (
+ <>
+ {contentVariants.map((variant) => (
+
+ Important message to explain a form or a section of a form.
+
+ ))}
+ >
+);
+
+export const Emotion: StoryFn = Template.bind({});
+Emotion.args = {
+ FormBanner: emotion.FormBanner
+} satisfies LayoutComponents;
+Emotion.parameters = { useEmotion: true };
+
+export const Class: StoryFn = Template.bind({});
+Class.args = {
+ FormBanner: css.FormBanner
+} satisfies LayoutComponents;
+Class.parameters = { useEmotion: false };