- This is a modal, doing modal things.
-
+ This is a modal, doing modal things.
+
This is linked text in the modal
-
-
+
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
@@ -82,12 +83,12 @@ export const LongContentWithScrolling = () => {
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
-
- This is a modal, doing modal things.
-
+
+ This is a modal, doing modal things.
+
This is some more linked text in the modal
-
-
+
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
@@ -95,12 +96,12 @@ export const LongContentWithScrolling = () => {
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
-
- This is a modal, doing modal things.
-
+
+ This is a modal, doing modal things.
+
This is a button
-
-
+
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
@@ -108,7 +109,7 @@ export const LongContentWithScrolling = () => {
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
-
+
Show Modal
@@ -184,10 +185,10 @@ export const ModalContentUpdate = () => {
{page === 1 && (
<>
-
Page one
-
+ Page one
+
This is linked text in the modal
-
+
{
/>
{showHidden && Hidden Button }
+
Go to Page 2
@@ -210,11 +212,11 @@ export const ModalContentUpdate = () => {
{page === 2 && (
<>
- Page two
-
+ Page two
+
Random button 1 {' '}
Random button 2
-
+
Go to Page 1
>
)}
@@ -248,11 +250,13 @@ export const NoHeaderOrFocusableContent = () => {
onClose={onModalNoFocusClose}
isOpen={showModalNoFocus}
>
- This modal has no header and nothing focusable.
-
+
+ This modal has no header and nothing focusable.
+
+
Consider the usability implications before implementing a modal like
this. A modal should have something actionable inside it.
-
+
Show Modal with nothing focusable
@@ -276,16 +280,16 @@ export const ModalInAModal = () => {
}}
isOpen={showModal}
>
- This is a modal, doing modal things.
-
+ This is a modal, doing modal things.
+
This is linked text in the modal
-
-
+
+
This is a button
-
-
+
+
This is some more linked text in the modal
-
+
{
]}
isClearable
/>
-
+
setShowModal2(true)}>Show Modal 2
-
+
setShowModal(true)} ref={buttonRef}>
Show Modal
@@ -324,7 +328,7 @@ export const ModalInAModal = () => {
onClose={() => setShowModal2(false)}
isOpen={showModal2}
>
- This is modal 2
+ This is modal 2
1
2
@@ -418,10 +422,12 @@ export const Inverse = () => {
isOpen={showModal}
isInverse
>
- This is an inverse modal, doing modal things.
-
+
+ This is an inverse modal, doing modal things.
+
+
This is a button
-
+
setShowModal(true)} ref={buttonRef} isInverse>
diff --git a/packages/react-magma-dom/src/components/Modal/Modal.tsx b/packages/react-magma-dom/src/components/Modal/Modal.tsx
index 69c76d94a..127e1d01e 100644
--- a/packages/react-magma-dom/src/components/Modal/Modal.tsx
+++ b/packages/react-magma-dom/src/components/Modal/Modal.tsx
@@ -160,6 +160,17 @@ const ModalContent = styled.div`
}
`;
+const ModalHeader = styled.div<{ theme?: ThemeInterface }>`
+ padding: ${props => props.theme.spaceScale.spacing05}
+ ${props => props.theme.spaceScale.spacing05} 0
+ ${props => props.theme.spaceScale.spacing05};
+ @media (min-width: ${props => props.theme.breakpoints.small}px) {
+ padding: ${props => props.theme.spaceScale.spacing06}
+ ${props => props.theme.spaceScale.spacing06} 0
+ ${props => props.theme.spaceScale.spacing06};
+ }
+`;
+
const ModalWrapper = styled.div<{ theme?: ThemeInterface }>`
padding: ${props => props.theme.spaceScale.spacing05};
@media (min-width: ${props => props.theme.breakpoints.small}px) {
@@ -366,7 +377,7 @@ export const Modal = React.forwardRef(
theme={theme}
>
{header && (
-
+
{header && (
(
{header}
)}
-
+
)}
{children}
diff --git a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.stories.tsx b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.stories.tsx
index 39f909720..d4111b771 100644
--- a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.stories.tsx
+++ b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.stories.tsx
@@ -4,6 +4,10 @@ import { CardBody } from '../Card/CardBody';
import { NativeSelect, NativeSelectProps } from '.';
import { Story, Meta } from '@storybook/react/types-6-0';
import { LabelPosition } from '../Label';
+import { Tooltip } from '../Tooltip';
+import { IconButton } from '../IconButton';
+import { HelpIcon } from 'react-magma-icons';
+import { ButtonSize, ButtonType, ButtonVariant } from '../Button';
const Template: Story = args => (
@@ -53,6 +57,39 @@ Disabled.args = {
disabled: true,
};
+const WithContentTemplate: Story = args => {
+ const helpLinkLabel = 'Learn more';
+ const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+ };
+ return (
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ >
+ Red
+ Green
+ Blue
+
+ );
+};
+
+export const WithContent = WithContentTemplate.bind({});
+WithContent.args = {
+ ...Default.args,
+};
+
export const HasError = Template.bind({});
HasError.args = {
...Default.args,
diff --git a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.test.js b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.test.js
index a82468215..093819070 100644
--- a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.test.js
+++ b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.test.js
@@ -4,10 +4,15 @@ import { magma } from '../../theme/magma';
import { NativeSelect } from '.';
import { render } from '@testing-library/react';
import { transparentize } from 'polished';
+import { Tooltip } from '../Tooltip';
+import { IconButton } from '../IconButton';
+import { HelpIcon } from 'react-magma-icons';
+import { ButtonSize, ButtonType, ButtonVariant } from '../Button';
describe('NativeSelect', () => {
+ const testId = 'test-id';
+
it('should find element by testId', () => {
- const testId = 'test-id';
const { getByTestId } = render(
);
@@ -28,7 +33,6 @@ describe('NativeSelect', () => {
});
it('should render a disabled select', () => {
- const testId = 'test-id';
const { getByTestId } = render(
);
@@ -40,7 +44,6 @@ describe('NativeSelect', () => {
});
it('should render a disabled inverse select', () => {
- const testId = 'test-id';
const { getByTestId } = render(
);
@@ -52,7 +55,6 @@ describe('NativeSelect', () => {
});
it('should render a default border', () => {
- const testId = 'test-id';
const { getByTestId } = render(
);
@@ -64,7 +66,6 @@ describe('NativeSelect', () => {
});
it('should render a default inverse border', () => {
- const testId = 'test-id';
const { getByTestId } = render(
);
@@ -76,7 +77,6 @@ describe('NativeSelect', () => {
});
it('should render an error state', () => {
- const testId = 'test-id';
const errorMessage = 'This is an error';
const { getByTestId, getByText } = render(
@@ -91,14 +91,9 @@ describe('NativeSelect', () => {
});
it('should render an inverse error state', () => {
- const testId = 'test-id';
const errorMessage = 'This is an error';
const { getByTestId, getByText } = render(
-
+
);
expect(getByTestId(testId).parentElement).toHaveStyleRule(
@@ -108,4 +103,61 @@ describe('NativeSelect', () => {
expect(getByText(errorMessage)).toBeInTheDocument();
});
+
+ describe('additional content', () => {
+ const helpLinkLabel = 'Learn more';
+
+ const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+ };
+
+ it('Should accept additional content to the right of the native select label', () => {
+ const { getByTestId } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ testId="Icon Button"
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ />
+ );
+ expect(getByTestId(testId)).toBeInTheDocument();
+ expect(getByTestId('Icon Button')).toBeInTheDocument();
+ });
+
+ it(`Should display additional content inline with the native select label when labelPosition is set to 'left'`, () => {
+ const { getByTestId } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ testId="Icon Button"
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ />
+ );
+ expect(getByTestId(`${testId}-form-field-container`)).toHaveStyleRule(
+ 'display',
+ 'flex'
+ );
+ });
+ });
});
diff --git a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.tsx b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.tsx
index 93b00d60d..fe5d66d1f 100644
--- a/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.tsx
+++ b/packages/react-magma-dom/src/components/NativeSelect/NativeSelect.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import styled from '../../theme/styled';
-
+import { css } from '@emotion/core';
import { inputBaseStyles, inputWrapperStyles } from '../InputBase';
import {
FormFieldContainer,
@@ -13,6 +13,7 @@ import { useIsInverse } from '../../inverse';
import { useGenerateId } from '../../utils';
import { ThemeInterface } from '../../theme/magma';
import { transparentize } from 'polished';
+import { LabelPosition } from '../Label';
/**
* @children required
@@ -20,6 +21,10 @@ import { transparentize } from 'polished';
export interface NativeSelectProps
extends Omit,
React.SelectHTMLAttributes {
+ /**
+ * Content above the select. For use with Icon Buttons to relay information.
+ */
+ additionalContent?: React.ReactNode;
/**
* @internal
*/
@@ -75,9 +80,41 @@ const StyledNativeSelect = styled.select<{
}
`;
+const StyledFormFieldContainer = styled(FormFieldContainer)<{
+ additionalContent?: React.ReactNode;
+ hasLabel?: boolean;
+ labelPosition?: LabelPosition;
+}>`
+ display: ${props =>
+ props.labelPosition === LabelPosition.left ? 'flex' : ''};
+
+ ${props =>
+ props.additionalContent &&
+ css`
+ flex: 1;
+ label {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ `}
+`;
+
+const StyledAdditionalContentWrapper = styled.div`
+ align-items: center;
+ display: flex;
+ label {
+ margin: 0 ${props => props.theme.spaceScale.spacing03} 0 0;
+ }
+ button {
+ margin: 0 0 0 ${props => props.theme.spaceScale.spacing03};
+ }
+`;
+
export const NativeSelect = React.forwardRef(
(props, ref) => {
const {
+ additionalContent,
children,
containerStyle,
disabled,
@@ -100,40 +137,73 @@ export const NativeSelect = React.forwardRef(
const id = useGenerateId(defaultId);
+ const hasLabel = !!labelText;
+
+ // If the labelPosition is set to 'left' then a wraps the FormFieldContainer, NativeSelectWrapper, and NativeSelect for proper styling alignment.
+ function AdditionalContentWrapper(props) {
+ if (
+ labelPosition === LabelPosition.left ||
+ (labelPosition === LabelPosition.top && !hasLabel)
+ ) {
+ return (
+
+ {props.children}
+
+ );
+ }
+ return props.children;
+ }
+
return (
-
-
+
+ {labelText}
+ {labelText && additionalContent}
+ >
+ ) : (
+ labelText
+ )
+ }
+ labelWidth={labelWidth}
isInverse={isInverse}
- theme={theme}
+ helperMessage={helperMessage}
+ messageStyle={messageStyle}
+ ref={ref}
>
-
- {children}
-
-
-
-
+
+ {children}
+
+
+
+
+ {(labelPosition === 'left' && additionalContent) ||
+ (!labelText && additionalContent)}
+
);
}
);
diff --git a/packages/react-magma-dom/src/components/Paragraph/Paragraph.stories.tsx b/packages/react-magma-dom/src/components/Paragraph/Paragraph.stories.tsx
index 0b6fea7d6..9e8916c28 100644
--- a/packages/react-magma-dom/src/components/Paragraph/Paragraph.stories.tsx
+++ b/packages/react-magma-dom/src/components/Paragraph/Paragraph.stories.tsx
@@ -2,77 +2,112 @@ import React from 'react';
import { Paragraph } from '.';
import { TypographyContextVariant, TypographyVisualStyle } from '../Typography';
import { Meta } from '@storybook/react/types-6-0';
+import { Card } from '../..';
export default {
component: Paragraph,
title: 'Paragraph',
+ argTypes: {
+ isInverse: {
+ control: {
+ type: 'boolean',
+ },
+ defaultValue: false,
+ },
+ noMargins: {
+ control: {
+ type: 'boolean',
+ },
+ defaultValue: false,
+ },
+ noBottomMargin: {
+ control: {
+ type: 'boolean',
+ },
+ defaultValue: false,
+ },
+ noTopMargin: {
+ control: {
+ type: 'boolean',
+ },
+ defaultValue: false,
+ },
+ },
} as Meta;
-export const Default = () => {
+export const Default = args => {
return (
- <>
-
- Body Large
+
+
+ Paragraph Body Large
-
- Body Medium
+
+ Paragraph Body Medium
-
- Body Small
+
+ Paragraph Body Small
-
- Body X-Small
+
+ Paragraph Body X-Small
- Narrative Large
+ Paragraph Narrative Large
- Narrative Medium
+ Paragraph Narrative Medium
- Narrative Small
+ Paragraph Narrative Small
- Narrative X-Small
+ Paragraph Narrative X-Small
- Expressive Large
+ Paragraph Expressive Large
- Expressive Medium
+ Paragraph Expressive Medium
- Expressive Small
+ Paragraph Expressive Small
- Expressive X-Small
+ Paragraph Expressive X-Small
- >
+
);
};
diff --git a/packages/react-magma-dom/src/components/Paragraph/Paragraph.test.js b/packages/react-magma-dom/src/components/Paragraph/Paragraph.test.js
index 22d9aa588..80eb09e40 100644
--- a/packages/react-magma-dom/src/components/Paragraph/Paragraph.test.js
+++ b/packages/react-magma-dom/src/components/Paragraph/Paragraph.test.js
@@ -117,6 +117,10 @@ describe('Paragraph', () => {
const text2 = 'Test Paragraph 2';
const text3 = 'Test Paragraph 3';
const text4 = 'Test Paragraph 4';
+ const text5 = 'Test Paragraph 5';
+ const text6 = 'Test Paragraph 6';
+ const text7 = 'Test Paragraph 7';
+ const text8 = 'Test Paragraph 8';
const { getByText } = render(
<>
@@ -131,13 +135,106 @@ describe('Paragraph', () => {
{text4}
+
+ {text5}
+
+
+ {text6}
+
+
+ {text7}
+
+
+ {text8}
+
+ >
+ );
+
+ expect(
+ getByText(
+ text1 || text2 || text3 || text4 || text5 || text6 || text7 || text8
+ )
+ ).toHaveStyleRule('margin', '0');
+ });
+
+ it('should render paragraphs with no top margin', () => {
+ const text1 = 'Test Paragraph 1';
+ const text2 = 'Test Paragraph 2';
+ const text3 = 'Test Paragraph 3';
+ const text4 = 'Test Paragraph 4';
+ const { getByText } = render(
+ <>
+
+ {text1}
+
+
+ {text2}
+
+
+ {text3}
+
+
+ {text4}
+
+ >
+ );
+
+ expect(getByText(text1)).toHaveStyleRule(
+ 'margin',
+ `0 0 ${magma.spaceScale.spacing06} 0`
+ );
+ expect(getByText(text2)).toHaveStyleRule(
+ 'margin',
+ `0 0 ${magma.spaceScale.spacing06} 0`
+ );
+ expect(getByText(text3)).toHaveStyleRule(
+ 'margin',
+ `0 0 ${magma.spaceScale.spacing05} 0`
+ );
+ expect(getByText(text4)).toHaveStyleRule(
+ 'margin',
+ `0 0 ${magma.spaceScale.spacing03} 0`
+ );
+ });
+
+ it('should render paragraphs with no bottom margin', () => {
+ const text1 = 'Test Paragraph 1';
+ const text2 = 'Test Paragraph 2';
+ const text3 = 'Test Paragraph 3';
+ const text4 = 'Test Paragraph 4';
+ const { getByText } = render(
+ <>
+
+ {text1}
+
+
+ {text2}
+
+
+ {text3}
+
+
+ {text4}
+
>
);
- expect(getByText(text1)).toHaveStyleRule('margin', '0');
- expect(getByText(text2)).toHaveStyleRule('margin', '0');
- expect(getByText(text3)).toHaveStyleRule('margin', '0');
- expect(getByText(text4)).toHaveStyleRule('margin', '0');
+ expect(getByText(text1)).toHaveStyleRule(
+ 'margin',
+ `${magma.spaceScale.spacing06} 0 0 0`
+ );
+ expect(getByText(text2)).toHaveStyleRule(
+ 'margin',
+ `${magma.spaceScale.spacing06} 0 0 0`
+ );
+ expect(getByText(text3)).toHaveStyleRule(
+ 'margin',
+ `${magma.spaceScale.spacing05} 0 0 0`
+ );
+ expect(getByText(text4)).toHaveStyleRule(
+ 'margin',
+ `${magma.spaceScale.spacing03} 0 0 0`
+ );
});
it('Does not violate accessibility standards', () => {
diff --git a/packages/react-magma-dom/src/components/Paragraph/index.tsx b/packages/react-magma-dom/src/components/Paragraph/index.tsx
index f0291637b..1b0ce1f5a 100644
--- a/packages/react-magma-dom/src/components/Paragraph/index.tsx
+++ b/packages/react-magma-dom/src/components/Paragraph/index.tsx
@@ -29,6 +29,16 @@ export interface ParagraphProps
* @default false
*/
noMargins?: boolean;
+ /**
+ * If true, the component will not have the default bottom margin and instead will have a value of 0
+ * @default false
+ */
+ noBottomMargin?: boolean;
+ /**
+ * If true, the component will not have the default top margin and instead will have a value of 0
+ * @default false
+ */
+ noTopMargin?: boolean;
/**
* @internal
*/
diff --git a/packages/react-magma-dom/src/components/Select/MultiSelect.tsx b/packages/react-magma-dom/src/components/Select/MultiSelect.tsx
index a98e9499f..677b44644 100644
--- a/packages/react-magma-dom/src/components/Select/MultiSelect.tsx
+++ b/packages/react-magma-dom/src/components/Select/MultiSelect.tsx
@@ -12,6 +12,7 @@ import { I18nContext } from '../../i18n';
export function MultiSelect(props: MultiSelectProps) {
const {
+ additionalContent,
ariaDescribedBy,
components: customComponents,
errorMessage,
@@ -160,6 +161,7 @@ export function MultiSelect(props: MultiSelectProps) {
return (
> = args => (
@@ -24,6 +28,11 @@ export default {
type: 'number',
},
},
+ isLabelVisuallyHidden: {
+ control: {
+ type: 'boolean',
+ },
+ },
},
} as Meta;
@@ -61,6 +70,40 @@ export const Multi = (props: MultiSelectProps) => (
/>
);
+const helpLinkLabel = 'Learn more';
+const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+};
+
+const WithContentTemplate: Story = args => (
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelText="Helper icon"
+ {...args}
+ items={[
+ { label: 'Red', value: 'red' },
+ { label: 'Blue', value: 'blue' },
+ { label: 'Green', value: 'green' },
+ ]}
+ />
+);
+
+export const WithContent = WithContentTemplate.bind({});
+WithContent.args = {
+ isMulti: false,
+};
+
export const ErrorMessage = Template.bind({});
ErrorMessage.args = {
...Default.args,
diff --git a/packages/react-magma-dom/src/components/Select/Select.test.js b/packages/react-magma-dom/src/components/Select/Select.test.js
index 53ae186cf..0d7109c5a 100644
--- a/packages/react-magma-dom/src/components/Select/Select.test.js
+++ b/packages/react-magma-dom/src/components/Select/Select.test.js
@@ -4,6 +4,11 @@ import { Select } from '.';
import { defaultI18n } from '../../i18n/default';
import { magma } from '../../theme/magma';
import { Modal } from '../Modal';
+import { Tooltip } from '../Tooltip';
+import { IconButton } from '../IconButton';
+import { HelpIcon } from 'react-magma-icons';
+import { ButtonSize, ButtonType, ButtonVariant } from '../Button';
+import { LabelPosition } from '../Label';
describe('Select', () => {
const labelText = 'Label';
@@ -459,7 +464,11 @@ describe('Select', () => {
it('should show a left aligned label', () => {
const { getByTestId } = render(
-
+
);
expect(getByTestId('selectContainerElement')).toHaveStyleRule(
@@ -472,7 +481,7 @@ describe('Select', () => {
const { getByText } = render(
@@ -500,6 +509,124 @@ describe('Select', () => {
expect(getByTestId('customClearIndicator')).toBeInTheDocument();
});
+ describe('additional content', () => {
+ const helpLinkLabel = 'Learn more';
+
+ const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+ };
+
+ it('Should accept additional content', () => {
+ const { getByTestId } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ testId={'Icon Button'}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelText={labelText}
+ items={items}
+ />
+ );
+
+ expect(getByTestId('Icon Button')).toBeInTheDocument();
+ });
+
+ it('Should accept additional content to the right of the multi-select label', () => {
+ const { getByTestId } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ testId={'Icon Button'}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelText={labelText}
+ isMulti
+ items={items}
+ />
+ );
+
+ expect(getByTestId('Icon Button')).toBeInTheDocument();
+ });
+
+ it('When label position is left, should accept additional content to display inline with the label and select', () => {
+ const { getByTestId } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelPosition={LabelPosition.left}
+ labelText={labelText}
+ items={items}
+ data-testid="selectContainerElement"
+ />
+ );
+
+ expect(getByTestId('selectContainerElement')).toBeInTheDocument();
+ expect(getByTestId('selectContainerElement')).toHaveStyleRule(
+ 'display',
+ 'flex'
+ );
+ });
+
+ it('When label position is left and isLabelVisuallyHidden is true, should accept additional content to display along select with a visually hidden label', () => {
+ const { getByTestId, getByText } = render(
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ isLabelVisuallyHidden
+ labelPosition={LabelPosition.left}
+ labelText={labelText}
+ items={items}
+ data-testid="selectContainerElement"
+ />
+ );
+
+ expect(getByText(labelText)).toHaveStyleRule('height', '1px');
+
+ expect(getByTestId('selectContainerElement')).toBeInTheDocument();
+ expect(getByTestId('selectContainerElement')).toHaveStyleRule(
+ 'display',
+ 'flex'
+ );
+ });
+ });
+
describe('events', () => {
it('onBlur', () => {
const onBlur = jest.fn();
diff --git a/packages/react-magma-dom/src/components/Select/Select.tsx b/packages/react-magma-dom/src/components/Select/Select.tsx
index a84febd4d..b0fb88df2 100644
--- a/packages/react-magma-dom/src/components/Select/Select.tsx
+++ b/packages/react-magma-dom/src/components/Select/Select.tsx
@@ -14,6 +14,7 @@ import { useForkedRef } from '../../utils';
export function Select(props: SelectProps) {
const {
+ additionalContent,
ariaDescribedBy,
components: customComponents,
defaultSelectedItem,
@@ -159,6 +160,7 @@ export function Select(props: SelectProps) {
return (
`
display: ${props =>
- props.labelPosition == LabelPosition.left ? 'flex' : 'block'};
+ props.labelPosition === LabelPosition.left ||
+ (props.isLabelVisuallyHidden && LabelPosition.top)
+ ? 'flex'
+ : 'block'};
position: relative;
label {
flex-basis: ${props =>
@@ -25,6 +31,7 @@ const InputMessageContainer = styled.div`
`;
interface SelectContainerInterface {
+ additionalContent?: React.ReactNode;
children: React.ReactNode[];
containerStyle?: React.CSSProperties;
errorMessage?: React.ReactNode;
@@ -41,8 +48,43 @@ interface SelectContainerInterface {
messageStyle?: React.CSSProperties;
}
+const StyledAdditionalContentWrapper = styled.div<{
+ labelPosition?: LabelPosition;
+ theme?: ThemeInterface;
+}>`
+ align-items: center;
+ display: flex;
+ flex: 1;
+ justify-content: space-between;
+ label {
+ margin: ${props =>
+ props.labelPosition === LabelPosition.left
+ ? `0 ${props.theme.spaceScale.spacing03} 0 0`
+ : ''};
+ }
+ button {
+ bottom: ${props =>
+ props.labelPosition !== LabelPosition.left ? `6px` : ''};
+ }
+`;
+
+const StyledAdditionalContent = styled.div<{
+ labelPosition?: LabelPosition;
+ theme?: ThemeInterface;
+}>`
+ display: flex;
+ align-items: center;
+ button {
+ margin: ${props =>
+ props.labelPosition === LabelPosition.left
+ ? `0 0 0 ${props.theme.spaceScale.spacing03}`
+ : ''};
+ }
+`;
+
export function SelectContainer(props: SelectContainerInterface) {
const {
+ additionalContent,
children,
descriptionId,
errorMessage,
@@ -59,24 +101,63 @@ export function SelectContainer(props: SelectContainerInterface) {
const hasError = !!errorMessage;
+ const theme = React.useContext(ThemeContext);
+
+ // If the labelPosition is set to 'top' (default) then a wraps the Label and additional content for proper styling alignment.
+ function AdditionalContentWrapper(props) {
+ if (
+ labelPosition !== LabelPosition.left &&
+ !isLabelVisuallyHidden &&
+ additionalContent
+ ) {
+ return (
+
+ {props.children}
+ {additionalContent}
+
+ );
+ }
+ return props.children;
+ }
+
+ // If the labelPosition is set to LabelPosition.left then the label, select, and additional content display inline.
+ function additionalItemRightAlign() {
+ if (
+ (labelPosition === LabelPosition.left && additionalContent) ||
+ (labelPosition && isLabelVisuallyHidden && additionalContent)
+ ) {
+ return (
+
+ {additionalContent}
+
+ );
+ }
+ }
+
return (
-
- {isLabelVisuallyHidden ? (
- {labelText}
- ) : (
- labelText
- )}
-
+
+
+ {isLabelVisuallyHidden ? (
+ {labelText}
+ ) : (
+ labelText
+ )}
+
+
{children}
{!(
@@ -96,6 +177,7 @@ export function SelectContainer(props: SelectContainerInterface) {
)}
+ {additionalItemRightAlign()}
);
}
diff --git a/packages/react-magma-dom/src/components/Select/index.tsx b/packages/react-magma-dom/src/components/Select/index.tsx
index bf080e877..c248cf094 100644
--- a/packages/react-magma-dom/src/components/Select/index.tsx
+++ b/packages/react-magma-dom/src/components/Select/index.tsx
@@ -108,6 +108,10 @@ export interface InternalMultiProps
{
export interface SelectProps
extends UseSelectProps,
InternalSelectProps {
+ /**
+ * Content above the select. For use with Icon Buttons to relay information.
+ */
+ additionalContent?: React.ReactNode;
/**
* Id of the element that describes the select trigger button
*/
diff --git a/packages/react-magma-dom/src/components/Typography/index.tsx b/packages/react-magma-dom/src/components/Typography/index.tsx
index 5d94e0cc1..22903d68a 100644
--- a/packages/react-magma-dom/src/components/Typography/index.tsx
+++ b/packages/react-magma-dom/src/components/Typography/index.tsx
@@ -11,6 +11,8 @@ export interface TypographyProps
element?: string;
isInverse?: boolean;
noMargins?: boolean;
+ noBottomMargin?: boolean;
+ noTopMargin?: boolean;
ref?: any;
/**
* @internal
@@ -58,12 +60,23 @@ export function getBodyFontFamily(props) {
}
}
-export const colorStyles = props => css`
- color: ${props.isInverse
- ? props.theme.colors.neutral100
- : props.contextVariant === 'expressive'
- ? props.theme.colors.primary600
- : props.theme.colors.neutral700};
+export function getBaseFontColor(props, isHeading = false) {
+ if (props.isInverse) {
+ return props.theme.colors.neutral100;
+ }
+
+ // Expressive headings use primary color
+ if (
+ props.contextVariant === TypographyContextVariant.expressive &&
+ isHeading
+ ) {
+ return props.theme.colors.primary600;
+ }
+ return props.theme.colors.neutral700;
+}
+
+export const colorStyles = (props, isHeading: boolean) => css`
+ color: ${getBaseFontColor(props, isHeading)};
${props.color === TypographyColor.danger &&
!props.isInverse &&
@@ -104,7 +117,7 @@ ${props.color === TypographyColor.subdued &&
`;
const baseParagraphStyles = props => css`
- ${colorStyles(props)}
+ ${colorStyles(props, false)}
font-family: ${getBodyFontFamily(props)};
font-weight: normal;
`;
@@ -112,7 +125,13 @@ const baseParagraphStyles = props => css`
export const paragraphLargeStyles = props => css`
${baseParagraphStyles(props)}
- margin: ${props.noMargins ? '0' : `${props.theme.spaceScale.spacing06} 0`};
+ margin: ${props.noMargins
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing06} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing06} 0`
+ : `${props.theme.spaceScale.spacing06} 0`};
font-size: ${props.theme.typographyVisualStyles.bodyLarge.mobile.fontSize};
line-height: ${props.theme.typographyVisualStyles.bodyLarge.mobile
@@ -146,7 +165,13 @@ export const paragraphMediumStyles = props => css`
font-size: ${props.theme.typographyVisualStyles.bodyMedium.mobile.fontSize};
line-height: ${props.theme.typographyVisualStyles.bodyMedium.mobile
.lineHeight};
- margin: ${props.noMargins ? '0' : `${props.theme.spaceScale.spacing06} 0`};
+ margin: ${props.noMargins
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing06} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing06} 0`
+ : `${props.theme.spaceScale.spacing06} 0`};
@media (min-width: ${props.theme.breakpoints.small}px) {
font-size: ${props.theme.typographyVisualStyles.bodyMedium.desktop
@@ -164,7 +189,13 @@ export const paragraphSmallStyles = props => css`
.letterSpacing};
line-height: ${props.theme.typographyVisualStyles.bodySmall.mobile
.lineHeight};
- margin: ${props.noMargins ? '0' : `${props.theme.spaceScale.spacing05} 0`};
+ margin: ${props.noMargins
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing05} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
+ : `${props.theme.spaceScale.spacing05} 0`};
@media (min-width: ${props.theme.breakpoints.small}px) {
font-size: ${props.theme.typographyVisualStyles.bodySmall.desktop.fontSize};
@@ -183,7 +214,13 @@ export const paragraphXSmallStyles = props => css`
.letterSpacing};
line-height: ${props.theme.typographyVisualStyles.bodyXSmall.mobile
.lineHeight};
- margin: ${props.noMargins ? '0' : `${props.theme.spaceScale.spacing03} 0`};
+ margin: ${props.noMargins
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing03} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing03} 0`
+ : `${props.theme.spaceScale.spacing03} 0`};
@media (min-width: ${props.theme.breakpoints.small}px) {
font-size: ${props.theme.typographyVisualStyles.bodyXSmall.desktop
@@ -220,7 +257,7 @@ const baseHeadingStyles = props => css`
transition: border 0.1s linear;
}
- ${colorStyles(props)}
+ ${colorStyles(props, true)}
`;
export const heading2XLargeStyles = props => css`
@@ -252,7 +289,13 @@ export const headingXLargeStyles = props => css`
font-weight: ${props.theme.typographyVisualStyles.headingXLarge.fontWeight};
line-height: ${props.theme.typographyVisualStyles.headingXLarge.mobile
.lineHeight};
- margin: ${props.noMargins ? 0 : `0 0 ${props.theme.spaceScale.spacing05}`};
+ margin: ${props.noMargins
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing05} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
+ : `0 0 ${props.theme.spaceScale.spacing05}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
font-size: ${props.theme.typographyVisualStyles.headingXLarge.desktop
@@ -302,8 +345,13 @@ export const headingLargeStyles = props => css`
font-weight: ${props.theme.typographyVisualStyles.headingLarge.fontWeight};
line-height: ${props.theme.typographyVisualStyles.headingLarge.mobile
.lineHeight};
+
margin: ${props.noMargins
- ? 0
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing10} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
: `${props.theme.spaceScale.spacing10} 0 ${props.theme.spaceScale.spacing05}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
@@ -355,8 +403,13 @@ export const headingMediumStyles = props => css`
font-weight: ${props.theme.typographyVisualStyles.headingMedium.fontWeight};
line-height: ${props.theme.typographyVisualStyles.headingMedium.mobile
.lineHeight};
+
margin: ${props.noMargins
- ? 0
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing09} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
: `${props.theme.spaceScale.spacing09} 0 ${props.theme.spaceScale.spacing05}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
@@ -378,6 +431,8 @@ export const headingMediumStyles = props => css`
@media (min-width: ${props.theme.breakpoints.small}px) {
font-size: ${props.theme.typographyExpressiveVisualStyles.headingMedium
.desktop.fontSize};
+ font-weight: ${props.theme.typographyExpressiveVisualStyles.headingMedium
+ .fontWeight};
line-height: ${props.theme.typographyExpressiveVisualStyles.headingMedium
.desktop.lineHeight};
}
@@ -407,8 +462,13 @@ export const headingSmallStyles = props => css`
font-weight: ${props.theme.typographyVisualStyles.headingSmall.fontWeight};
line-height: ${props.theme.typographyVisualStyles.headingSmall.mobile
.lineHeight};
+
margin: ${props.noMargins
- ? 0
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing08} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
: `${props.theme.spaceScale.spacing08} 0 ${props.theme.spaceScale.spacing05}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
@@ -459,8 +519,13 @@ export const headingXSmallStyles = props => css`
font-weight: ${props.theme.typographyVisualStyles.headingXSmall.fontWeight};
line-height: ${props.theme.typographyVisualStyles.headingXSmall.mobile
.lineHeight};
+
margin: ${props.noMargins
- ? 0
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing06} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing05} 0`
: `${props.theme.spaceScale.spacing06} 0 ${props.theme.spaceScale.spacing05}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
@@ -515,8 +580,13 @@ export const heading2XSmallStyles = props => css`
line-height: ${props.theme.typographyVisualStyles.heading2XSmall.mobile
.lineHeight};
text-transform: uppercase;
+
margin: ${props.noMargins
- ? 0
+ ? '0'
+ : props.noBottomMargin
+ ? `${props.theme.spaceScale.spacing06} 0 0 0`
+ : props.noTopMargin
+ ? `0 0 ${props.theme.spaceScale.spacing03} 0`
: `${props.theme.spaceScale.spacing06} 0 ${props.theme.spaceScale.spacing03}`};
@media (min-width: ${props.theme.breakpoints.small}px) {
@@ -602,4 +672,5 @@ function getTypographyStyles(props) {
export const TypographyComponent = styled.p`
${props => getTypographyStyles(props)}
+ margin: ${props => (props.noBottomMargin && props.noTopMargin ? '0' : '')};
`;
diff --git a/packages/react-magma-dom/src/theme/magma.ts b/packages/react-magma-dom/src/theme/magma.ts
index 9f859dc95..a23f11222 100644
--- a/packages/react-magma-dom/src/theme/magma.ts
+++ b/packages/react-magma-dom/src/theme/magma.ts
@@ -69,7 +69,7 @@ export interface Colors {
focus: string;
focusInverse: string;
-
+
border: string;
borderInverse: string;
}
@@ -143,6 +143,7 @@ export interface TypeScale {
size13: TypeScaleSize;
size14: TypeScaleSize;
size15: TypeScaleSize;
+ size16: TypeScaleSize;
}
export interface VisualStyle {
@@ -291,6 +292,8 @@ export interface ThemeInterface {
headingFont: string;
iconSizes: IconSizes;
iterableColors: string[];
+ chartColors?: string[];
+ chartColorsInverse?: string[];
spacingMultiplier: number;
spaceScale: SpacingScale;
headingExpressiveFont: string;
@@ -352,11 +355,11 @@ const typeScale = {
},
size11: {
fontSize: '48px',
- lineHeight: '56px',
+ lineHeight: '64px',
},
size12: {
fontSize: '52px',
- lineHeight: '68px',
+ lineHeight: '64px',
},
size13: {
fontSize: '54px',
@@ -367,9 +370,13 @@ const typeScale = {
lineHeight: '72px',
},
size15: {
+ fontSize: '64px',
+ lineHeight: '84px',
+ },
+ size16: {
fontSize: '72px',
lineHeight: '84px',
- }
+ },
};
const primaryColors = {
@@ -522,7 +529,8 @@ export const magma = {
// Typography
typeScale: typeScale,
- typographyVisualStyles: { // Productive
+ typographyVisualStyles: {
+ // Productive
headingXLarge: {
mobile: typeScale.size07,
desktop: typeScale.size09,
@@ -572,43 +580,43 @@ export const magma = {
},
typographyExpressiveVisualStyles: {
heading2XLarge: {
- mobile: typeScale.size13,
+ mobile: typeScale.size11,
desktop: typeScale.size15,
- fontWeight: 600,
+ fontWeight: 500,
},
headingXLarge: {
- mobile: typeScale.size10,
- desktop: typeScale.size12,
- fontWeight: 400,
+ mobile: typeScale.size09,
+ desktop: typeScale.size11,
+ fontWeight: 600,
},
headingLarge: {
mobile: typeScale.size07,
desktop: typeScale.size09,
- fontWeight: 300,
+ fontWeight: 600,
},
headingMedium: {
mobile: typeScale.size06,
desktop: typeScale.size07,
- fontWeight: 300,
+ fontWeight: 600,
},
headingSmall: {
mobile: typeScale.size05,
desktop: typeScale.size06,
- fontWeight: 300,
+ fontWeight: 500,
},
headingXSmall: {
mobile: typeScale.size04,
desktop: typeScale.size05,
- fontWeight: 300,
+ fontWeight: 500,
},
heading2XSmall: {
mobile: typeScale.size03,
- desktop: typeScale.size03,
- fontWeight: 700,
+ desktop: typeScale.size04,
+ fontWeight: 500,
},
bodyLarge: {
mobile: typeScale.size05,
- desktop: typeScale.size06,
+ desktop: typeScale.size05,
},
bodyMedium: {
mobile: typeScale.size03,
@@ -756,6 +764,36 @@ export const magma = {
'#005249',
],
+ chartColors: [
+ '#009AF3',
+ '#E0004D',
+ '#1EA746',
+ '#FA6600',
+ '#B12FAD',
+ '#00A393',
+ '#005F96',
+ '#8F0033',
+ '#136A2D',
+ '#B84900',
+ '#711E6E',
+ '#005249',
+ ],
+
+ chartColorsInverse: [
+ '#1FB0FF',
+ '#FF337A',
+ '#65E000',
+ '#FF9147',
+ '#D45ED0',
+ '#00E0CA',
+ '#85D4FF',
+ '#FF99BD',
+ '#FFB685',
+ '#C7FF99',
+ '#E9AFE7',
+ '#99FFF5',
+ ],
+
tabs: {
approxTabSize: {
horizontal: 120,
diff --git a/packages/schema-renderer/CHANGELOG.md b/packages/schema-renderer/CHANGELOG.md
index 9fa02c988..65aff3661 100644
--- a/packages/schema-renderer/CHANGELOG.md
+++ b/packages/schema-renderer/CHANGELOG.md
@@ -1,5 +1,19 @@
# @react-magma/schema-renderer
+## 6.0.0-next.1
+
+### Patch Changes
+
+- Updated dependencies [c47fc18b4]
+ - react-magma-dom@4.3.0-next.2
+
+## 5.0.1-next.0
+
+### Patch Changes
+
+- Updated dependencies [fc3098851]
+ - react-magma-dom@4.2.1-next.0
+
## 5.0.0
## 5.0.0-next.0
diff --git a/packages/schema-renderer/package.json b/packages/schema-renderer/package.json
index d66693d4b..7fb15394c 100644
--- a/packages/schema-renderer/package.json
+++ b/packages/schema-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-magma/schema-renderer",
- "version": "5.0.0",
+ "version": "6.0.0-next.1",
"publishConfig": {
"access": "public"
},
@@ -27,7 +27,7 @@
"downshift": "^5.4.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-magma-dom": "^4.2.0-next.0",
+ "react-magma-dom": "^4.3.0-next.2",
"react-magma-icons": "^3.0.0",
"uuid": "^8.3.0"
},
@@ -41,7 +41,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-dropzone": "11.3.2",
- "react-magma-dom": "^4.2.0",
+ "react-magma-dom": "^4.3.0-next.2",
"react-magma-icons": "^3.0.0",
"tsdx": "^0.14.1",
"uuid": "^8.3.0"
diff --git a/patterns/header/CHANGELOG.md b/patterns/header/CHANGELOG.md
index 33ba816cf..89e996948 100644
--- a/patterns/header/CHANGELOG.md
+++ b/patterns/header/CHANGELOG.md
@@ -1,5 +1,19 @@
# Change Log
+## 8.0.0-next.1
+
+### Patch Changes
+
+- Updated dependencies [c47fc18b4]
+ - react-magma-dom@4.3.0-next.2
+
+## 7.0.1-next.0
+
+### Patch Changes
+
+- Updated dependencies [fc3098851]
+ - react-magma-dom@4.2.1-next.0
+
## 7.0.0
## 7.0.0-next.0
diff --git a/patterns/header/package.json b/patterns/header/package.json
index 1deca80fe..32a478929 100644
--- a/patterns/header/package.json
+++ b/patterns/header/package.json
@@ -2,7 +2,7 @@
"publishConfig": {
"access": "public"
},
- "version": "7.0.0",
+ "version": "8.0.0-next.1",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
@@ -26,7 +26,7 @@
"downshift": "^5.4.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-magma-dom": "^4.2.0-next.0",
+ "react-magma-dom": "^4.3.0-next.2",
"react-magma-icons": "^3.0.0",
"uuid": "^8.3.0"
},
@@ -38,7 +38,7 @@
"downshift": "^5.4.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-magma-dom": "^4.2.0",
+ "react-magma-dom": "^4.3.0-next.2",
"react-magma-icons": "^3.0.0",
"uuid": "^8.3.0"
},
diff --git a/website/react-magma-docs/CHANGELOG.md b/website/react-magma-docs/CHANGELOG.md
index ae59f307b..aa52bfd07 100644
--- a/website/react-magma-docs/CHANGELOG.md
+++ b/website/react-magma-docs/CHANGELOG.md
@@ -1,5 +1,81 @@
# Change Log
+## 5.0.5-next.9
+
+### Patch Changes
+
+- Updated dependencies [3fc9e50ca]
+ - react-magma-dom@4.3.0-next.7
+
+## 5.0.5-next.8
+
+### Patch Changes
+
+- Updated dependencies [421b9091a]
+ - react-magma-dom@4.3.0-next.6
+
+## 5.0.5-next.7
+
+### Patch Changes
+
+- Updated dependencies [8fa4252f4]
+ - react-magma-dom@4.3.0-next.5
+
+## 5.0.5-next.6
+
+### Patch Changes
+
+- 7f1d9b96c: fix(Select/NativeSelect): Update AdditionalContent CodeSandbox examples
+
+## 5.0.5-next.5
+
+### Patch Changes
+
+- Updated dependencies [1fb88b6fc]
+ - react-magma-dom@4.3.0-next.4
+
+## 5.0.5-next.4
+
+### Patch Changes
+
+- Updated dependencies [5e438ab0a]
+ - react-magma-dom@4.3.0-next.3
+
+## 5.0.5-next.3
+
+### Patch Changes
+
+- Updated dependencies [c47fc18b4]
+ - react-magma-dom@4.3.0-next.2
+ - @react-magma/charts@6.0.0-next.1
+ - @react-magma/dropzone@6.0.0-next.1
+ - @react-magma/schema-renderer@6.0.0-next.1
+ - @cengage-patterns/header@8.0.0-next.1
+
+## 5.0.5-next.2
+
+### Patch Changes
+
+- Updated dependencies [e6ca26b27]
+ - react-magma-dom@4.2.1-next.1
+
+## 5.0.5-next.1
+
+### Patch Changes
+
+- Updated dependencies [fc3098851]
+ - react-magma-dom@4.2.1-next.0
+ - @react-magma/charts@5.0.1-next.0
+ - @react-magma/dropzone@5.0.1-next.0
+ - @react-magma/schema-renderer@5.0.1-next.0
+ - @cengage-patterns/header@7.0.1-next.0
+
+## 5.0.5-next.0
+
+### Patch Changes
+
+- 408f3d5d0: build: Resolve merge conflicts when pulling main -> dev
+
## 5.0.4
### Patch Changes
diff --git a/website/react-magma-docs/package.json b/website/react-magma-docs/package.json
index b8ffd7c3b..7f87f9822 100644
--- a/website/react-magma-docs/package.json
+++ b/website/react-magma-docs/package.json
@@ -1,7 +1,7 @@
{
"name": "react-magma-docs",
"description": "React Magma docs",
- "version": "5.0.4",
+ "version": "5.0.5-next.9",
"private": true,
"repository": {
"type": "git",
@@ -11,15 +11,15 @@
"homepage": "https://react-magma.cengage.com",
"dependencies": {
"@babel/plugin-transform-react-jsx": "7.10.4",
- "@cengage-patterns/header": "7.0.0",
+ "@cengage-patterns/header": "8.0.0-next.1",
"@data-driven-forms/react-form-renderer": "^3.6.0",
"@emotion/core": "^10.1.1",
"@emotion/styled": "^10.0.27",
"@mdx-js/mdx": "^1.5.5",
"@mdx-js/react": "^1.5.5",
- "@react-magma/charts": "^5.0.0",
- "@react-magma/dropzone": "5.0.0",
- "@react-magma/schema-renderer": "^5.0.0",
+ "@react-magma/charts": "^6.0.0-next.1",
+ "@react-magma/dropzone": "6.0.0-next.1",
+ "@react-magma/schema-renderer": "^6.0.0-next.1",
"buble": "0.19.4",
"buffer": "^6.0.3",
"core-js": "^3.1.4",
@@ -49,7 +49,7 @@
"react-focus-lock": "^2.9.2",
"react-helmet": "5.2.0",
"react-live": "^2.2.1",
- "react-magma-dom": "4.2.0",
+ "react-magma-dom": "4.3.0-next.7",
"react-magma-icons": "^3.0.0",
"react-spring": "6.1.9",
"semver": "^7.3.4",
diff --git a/website/react-magma-docs/src/pages/api-intro/changelog.mdx b/website/react-magma-docs/src/pages/api-intro/changelog.mdx
index a44e9d6f3..6fbe781bb 100644
--- a/website/react-magma-docs/src/pages/api-intro/changelog.mdx
+++ b/website/react-magma-docs/src/pages/api-intro/changelog.mdx
@@ -5,7 +5,47 @@ order: 4
+## 4.3.0
+### Minor Changes
+
+- 8fa4252f4: feat(Paragraph): New `noTopMargin` and `noBottomMargin` props that allow customization of which margin to remove
+- c47fc18b4: feat(Select/NativeSelect): New `additionalContent` prop to provide the ability to add extra content inline with the label similar to the Input component
+- 5e438ab0a: fix(Select): Fixed alignment issues in Select regarding additional content icon.
+- 5e438ab0a: fix(NativeSelect): Fixed duplicate additional content in Native Select.
+
+### Patch Changes
+
+- 421b9091a: fix(Modal): Fixed bottom padding on the Modal header
+- 1fb88b6fc: fix: Updates to the expressive font styles for both desktop and mobile
+- fc3098851: build(deps): bump browserify-sign from 4.2.1 to 4.2.2
+
+## 4.2.0
+
+### Minor Changes
+
+- de22be548: feat(DropdownExpandableMenu): A new menu item display for the Dropdown component which enables expandable lists by one level
+- de22be548: feat(TablePagination): TablePagination component will hide rows per page select when no onRowsPerPageChange argument passed
+
+### Patch Changes
+
+- de22be548: fix(DropdownContent): Handle `false` as child
+- de22be548: fix(StyledLabel/TabPanel): Update various labels and TabPanel content to be neutral700 (instead of neutral500)
+- de22be548: fix(Select/Combobox/Dropdown/DatePicker): Added support for closing components that have menus with the escape key inside of modals while retaining an open modal state.
+- de22be548: fix(PasswordInput): Update placement of Show/Hide button on Large input size
+- de22be548: fix(RadioGroup): Radio Group label is now a span to improve a11y
+- de22be548: fix(Input): Update Input height to match button sizes: 40px (instead of 42px) and 56px (instead of 58px)
+- de22be548: fix(NativeSelect): Update NativeSelect height to match button sizes: 40px (instead of 42px)
+- de22be548: fix(Table/DataGrid): Update Ascending (point up) and Descending (point down) arrows to match other design systems
+- de22be548: fix(Modal): Update padding so it's equal on all sides (16px small viewport or 24px for large)
+
+## 4.1.1
+
+### Patch Changes
+
+- 0d718be80: fix(Input Base): Fixed case where default value of `0` did not render the default value in the input field
+- 0d718be80: fix(Input/Textarea): Fix `maxLength` console warning regarding passing a boolean attribute
+- 0d718be80: docs(tabs): Update TabProps to remove `isActive`-- this component does not use it. Use `activeIndex` on the `TabsContainer` to indicate the active tab
## 4.1.0
diff --git a/website/react-magma-docs/src/pages/api-intro/styles-and-themes.mdx b/website/react-magma-docs/src/pages/api-intro/styles-and-themes.mdx
index a2f5b60c7..1d8e42e3f 100644
--- a/website/react-magma-docs/src/pages/api-intro/styles-and-themes.mdx
+++ b/website/react-magma-docs/src/pages/api-intro/styles-and-themes.mdx
@@ -516,24 +516,24 @@ typographyVisualStyles: {
},
typographyExpressiveVisualStyles: {
heading2XLarge: {
- mobile: typeScale.size13,
+ mobile: typeScale.size11,
desktop: typeScale.size15,
- fontWeight: 600,
+ fontWeight: 500,
},
headingXLarge: {
- mobile: typeScale.size10,
- desktop: typeScale.size12,
- fontWeight: 400,
+ mobile: typeScale.size09,
+ desktop: typeScale.size11,
+ fontWeight: 600,
},
headingLarge: {
mobile: typeScale.size07,
desktop: typeScale.size09,
- fontWeight: 300,
+ fontWeight: 600,
},
headingMedium: {
mobile: typeScale.size06,
desktop: typeScale.size07,
- fontWeight: 300,
+ fontWeight: 600,
},
...
},
diff --git a/website/react-magma-docs/src/pages/api/modal.mdx b/website/react-magma-docs/src/pages/api/modal.mdx
index b670e794e..7135a58f0 100644
--- a/website/react-magma-docs/src/pages/api/modal.mdx
+++ b/website/react-magma-docs/src/pages/api/modal.mdx
@@ -27,7 +27,13 @@ This can be done by supplementing the button label or link text with "(opens mod
```tsx
import React from 'react';
-import { Button, Hyperlink, Modal, VisuallyHidden } from 'react-magma-dom';
+import {
+ Button,
+ Hyperlink,
+ Modal,
+ Paragraph,
+ VisuallyHidden,
+} from 'react-magma-dom';
export function Example() {
const [showModal, setShowModal] = React.useState(false);
const buttonRef = React.useRef();
@@ -40,17 +46,17 @@ export function Example() {
return (
<>
- This is a modal, doing modal things.
-
+ This is a modal, doing modal things.
+
This is linked text in the modal
-
-
+
+
This is a button
-
-
+
+
This is some more linked text in the
modal
-
+
setShowModal(true)} ref={buttonRef}>
Show Modal
@@ -72,6 +78,7 @@ import {
ButtonSize,
Modal,
ModalSize,
+ Paragraph,
VisuallyHidden,
ButtonGroup,
} from 'react-magma-dom';
@@ -92,7 +99,9 @@ export function Example() {
}}
isOpen={showSmallModal}
>
- This is a small modal, doing small modal things.
+
+ This is a small modal, doing small modal things.
+
- This is a large modal, doing large modal things.
+
+ This is a large modal, doing large modal things.
+
@@ -142,6 +153,7 @@ import {
Button,
Modal,
ModalSize,
+ Paragraph,
VisuallyHidden,
ButtonGroup,
ButtonGroupAlignment,
@@ -162,7 +174,7 @@ export function Example() {
}}
isOpen={showModal}
>
- This modal has no header.
+ This modal has no header.
setShowModal(false)}>OK
@@ -176,7 +188,7 @@ export function Example() {
}}
isOpen={showModalHeader}
>
- This modal has no header.
+ This modal has no header.
setShowModalHeader(false)}>OK
@@ -202,7 +214,7 @@ The close button can be hidden by using the `isCloseButtonHidden` prop. If this
```tsx
import React from 'react';
-import { Button, Modal } from 'react-magma-dom';
+import { Button, Modal, Paragraph } from 'react-magma-dom';
export function Example() {
const [showModal, setShowModal] = React.useState(false);
const buttonRef = React.useRef();
@@ -218,7 +230,9 @@ export function Example() {
}}
isOpen={showModal}
>
- The standard modal close button is hidden.
+
+ The standard modal close button is hidden.
+
setShowModal(false)}>Close this Dialog
setShowModal(true)} ref={buttonRef}>
@@ -235,7 +249,7 @@ If you would like to add a custom close button to the `Modal` be sure not to use
```tsx
import React from 'react';
-import { Button, Modal, VisuallyHidden } from 'react-magma-dom';
+import { Button, Modal, Paragraph, VisuallyHidden } from 'react-magma-dom';
export function Example() {
const [showModal, setShowModal] = React.useState(false);
const [magmaCloseCalledTimes, setMagmaCloseCalledTimes] = React.useState(0);
@@ -261,12 +275,12 @@ export function Example() {
Lorem ipsum dolar sit amet
Close Modal
-
+
Magma Close Called Times: {magmaCloseCalledTimes}
-
-
+
+
Internal Close Called Times: {internalCloseCalledTimes}
-
+
setShowModal(true)} ref={buttonRef}>
Show Modal (opens modal dialog)
@@ -281,7 +295,13 @@ Although we don't recommend using nested modals, the ability for one nested moda
```tsx
import React from 'react';
-import { Button, Modal, ModalSize, VisuallyHidden } from 'react-magma-dom';
+import {
+ Button,
+ Modal,
+ ModalSize,
+ Paragraph,
+ VisuallyHidden,
+} from 'react-magma-dom';
export function Example() {
const [showModal, setShowModal] = React.useState(false);
const [showModal2, setShowModal2] = React.useState(false);
@@ -295,7 +315,7 @@ export function Example() {
}}
isOpen={showModal}
>
- This is a modal, doing modal things.
+ This is a modal, doing modal things.
setShowModal2(true)}>Show Modal 2
@@ -309,7 +329,7 @@ export function Example() {
onClose={() => setShowModal2(false)}
isOpen={showModal2}
>
- This is modal 2
+ This is modal 2
>
);
@@ -324,6 +344,7 @@ import {
Button,
Hyperlink,
Modal,
+ Paragraph,
VisuallyHidden,
Card,
CardBody,
@@ -343,24 +364,26 @@ export function Example() {
isOpen={showModal}
isInverse
>
- This is a modal, doing modal things.
-
+
+ This is a modal, doing modal things.
+
+
This is{' '}
linked text
{' '}
in the modal
-
-
+
+
This is a button
-
-
+
+
This is{' '}
some more linked text
{' '}
in the modal
-
+
diff --git a/website/react-magma-docs/src/pages/api/native-select.mdx b/website/react-magma-docs/src/pages/api/native-select.mdx
index 5dde19a83..94fd82f45 100644
--- a/website/react-magma-docs/src/pages/api/native-select.mdx
+++ b/website/react-magma-docs/src/pages/api/native-select.mdx
@@ -22,7 +22,7 @@ import { NativeSelect } from 'react-magma-dom';
export function Example() {
return (
-
+
Red
Green
Blue
@@ -47,7 +47,11 @@ export function Example() {
Changed Value: {' '}
{message}
-
+
Choose Color
Red
Green
@@ -65,7 +69,11 @@ import React from 'react';
import { NativeSelect } from 'react-magma-dom';
export function Example() {
return (
-
+
Choose Color
Red
Green
@@ -83,7 +91,7 @@ import { NativeSelect } from 'react-magma-dom';
export function Example() {
return (
-
+
Red
Green
Blue
@@ -100,7 +108,11 @@ import { NativeSelect } from 'react-magma-dom';
export function Example() {
return (
-
+
Red
Green
Blue
@@ -120,6 +132,7 @@ export function Example() {
Red
Green
@@ -129,6 +142,81 @@ export function Example() {
}
```
+## Additional Content
+
+When a native select needs additional context related to the user, `additionalContent` allows child elements to help. It is encouraged to use this prop with a `Tooltip` wrapping an `IconButton`.
+
+By default, the child element will display inline with a `NativeSelect` label on the right.
+
+When `labelPosition` is set to `left`, the label, native select, and child elements all display inline.
+
+```tsx
+import React from 'react';
+import {
+ NativeSelect,
+ LabelPosition,
+ Tooltip,
+ IconButton,
+ ButtonSize,
+ ButtonType,
+ ButtonVariant,
+} from 'react-magma-dom';
+import { HelpIcon } from 'react-magma-icons';
+
+export function Example() {
+ const helpLinkLabel = 'Learn more';
+ const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+ };
+
+ return (
+ <>
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ >
+ Red
+ Green
+ Blue
+
+
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ >
+ Red
+ Green
+ Blue
+
+ >
+ );
+}
+```
+
## Inverse
The `isInverse` prop will render a dark background and light text. The children will
@@ -142,7 +230,11 @@ export function Example() {
return (
-
+
Red
Green
Blue
@@ -163,7 +255,12 @@ export function Example() {
return (
-
+
Red
Green
Blue
@@ -188,6 +285,7 @@ export function Example() {
labelText="Select this"
isInverse
errorMessage="This is an error"
+ fieldId="example-inverseError"
>
Red
Green
@@ -213,6 +311,7 @@ export function Example() {
labelText="Select this"
isInverse
helperMessage="Helper message appears here"
+ fieldId="example-inverseHelper"
>
Red
Green
diff --git a/website/react-magma-docs/src/pages/api/paragraph.mdx b/website/react-magma-docs/src/pages/api/paragraph.mdx
index 73cf75d82..d5c007e40 100644
--- a/website/react-magma-docs/src/pages/api/paragraph.mdx
+++ b/website/react-magma-docs/src/pages/api/paragraph.mdx
@@ -254,6 +254,68 @@ export function Example() {
}
```
+## No Top Margin
+
+When the `noTopMargin` prop is used, the element will have a top margin value of 0.
+
+```tsx
+import React from 'react';
+import { Paragraph, TypographyVisualStyle } from 'react-magma-dom';
+
+export function Example() {
+ return (
+ <>
+
+ Body large. Lorem ipsum dolar sit amet.
+
+
+
+ Body medium (default). Lorem ipsum dolar sit amet.
+
+
+
+ Body small. Lorem ipsum dolar sit amet.
+
+
+
+ Body x-small. Lorem ipsum dolar sit amet.
+
+ >
+ );
+}
+```
+
+## No Bottom Margin
+
+When the `noBottomMargin` prop is used, the element will have a bottom margin value of 0.
+
+```tsx
+import React from 'react';
+import { Paragraph, TypographyVisualStyle } from 'react-magma-dom';
+
+export function Example() {
+ return (
+ <>
+
+ Body large. Lorem ipsum dolar sit amet.
+
+
+
+ Body medium (default). Lorem ipsum dolar sit amet.
+
+
+
+ Body small. Lorem ipsum dolar sit amet.
+
+
+
+ Body x-small. Lorem ipsum dolar sit amet.
+
+ >
+ );
+}
+```
+
## Paragraph Props
**This component uses `forwardRef`. The ref is applied to the outer `p` element.**
diff --git a/website/react-magma-docs/src/pages/api/select.mdx b/website/react-magma-docs/src/pages/api/select.mdx
index e0cb4fca6..ced8eab7e 100644
--- a/website/react-magma-docs/src/pages/api/select.mdx
+++ b/website/react-magma-docs/src/pages/api/select.mdx
@@ -353,6 +353,84 @@ export function Example() {
}
```
+## Additional Content
+
+When a select needs additional context related to the user, `additionalContent` allows child elements to help. It is encouraged to use this prop with a `Tooltip` wrapping an `IconButton`.
+
+By default, the child element will display inline with a `Select` label on the right.
+
+When `labelPosition` is set to `left`, the label, select, and child elements all display inline.
+
+If no label is required, use `isLabelVisuallyHidden` and the same inline layout will persist.
+
+```tsx
+import React from 'react';
+import {
+ Select,
+ LabelPosition,
+ Tooltip,
+ IconButton,
+ ButtonSize,
+ ButtonType,
+ ButtonVariant,
+} from 'react-magma-dom';
+import { HelpIcon } from 'react-magma-icons';
+
+export function Example() {
+ const helpLinkLabel = 'Learn more';
+ const onHelpLinkClick = () => {
+ alert('Help link clicked!');
+ };
+
+ return (
+ <>
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelText="Default positioning"
+ items={[
+ { label: 'Red', value: 'red' },
+ { label: 'Blue', value: 'blue' },
+ { label: 'Green', value: 'green' },
+ ]}
+ />
+
+
+ }
+ onClick={onHelpLinkClick}
+ type={ButtonType.button}
+ size={ButtonSize.small}
+ variant={ButtonVariant.link}
+ />
+
+ }
+ labelPosition={LabelPosition.left}
+ labelText="Left positioning"
+ items={[
+ { label: 'Red', value: 'red' },
+ { label: 'Blue', value: 'blue' },
+ { label: 'Green', value: 'green' },
+ ]}
+ />
+ >
+ );
+}
+```
+
## Inverse
```tsx
diff --git a/website/react-magma-docs/src/pages/design-intro/typography.mdx b/website/react-magma-docs/src/pages/design-intro/typography.mdx
index 9135a22b9..9370d0995 100644
--- a/website/react-magma-docs/src/pages/design-intro/typography.mdx
+++ b/website/react-magma-docs/src/pages/design-intro/typography.mdx
@@ -292,7 +292,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Body / Large
Typeface: Work Sans
- Size: 24px / 1.5em
+ Size: 20px / 1.5em
Line-height: 32px / 2em
Weight: Regular / 400
Letter-spacing: 0px
@@ -331,9 +331,9 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Heading / 2X-Large
Typeface: Work Sans
- Size: 72px / 4.5em
+ Size: 64px / 4em
Line-height: 84px / 5.25em
- Weight: Semibold / 600
+ Weight: Medium / 500
Letter-spacing: 0px
@@ -341,9 +341,9 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Heading / 2X-Large
Typeface: Work Sans
-
Size: 54px / 3.375em
+
Size: 48px / 3em
Line-height: 64px / 4em
-
Weight: Semibold / 600
+
Weight: Medium / 500
Letter-spacing: 0px
@@ -362,9 +362,9 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Heading / X-Large
Typeface: Work Sans
- Size: 52px / 3.25em
- Line-height: 68px / 4.25em
- Weight: Regular / 400
+ Size: 48px / 3em
+ Line-height: 64px / 4em
+ Weight: Semibold / 600
Letter-spacing: 0px
@@ -372,9 +372,9 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Heading / X-Large
Typeface: Work Sans
-
Size: 42px / 2.625em
+
Size: 36px / 2.25em
Line-height: 48px / 3em
-
Weight: Regular / 400
+
Weight: Semibold / 600
Letter-spacing: 0px
@@ -395,7 +395,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 36px / 2.25em
Line-height: 48px / 3em
- Weight: Light / 300
+ Weight: Semibold / 600
Letter-spacing: 0px
@@ -405,7 +405,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 28px / 1.75em
Line-height: 40px / 2.5em
-
Weight: Light / 300
+
Weight: Semibold / 600
Letter-spacing: 0px
@@ -426,7 +426,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 28px / 1.75em
Line-height: 40px / 2.5em
- Weight: Light / 300
+ Weight: Semibold / 600
Letter-spacing: 0px
@@ -436,7 +436,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 24px / 1.5em
Line-height: 32px / 2em
-
Weight: Light / 300
+
Weight: Semibold / 600
Letter-spacing: 0px
@@ -457,7 +457,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 24px / 1.5em
Line-height: 32px / 2em
- Weight: Light / 300
+ Weight: Medium / 500
Letter-spacing: 0px
@@ -465,9 +465,9 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Heading / Small
Typeface: Work Sans
-
Size: 20px / 1.5em
+
Size: 20px / 1.25em
Line-height: 32px / 2em
-
Weight: Light / 300
+
Weight: Medium / 500
Letter-spacing: 0px
@@ -488,7 +488,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 20px / 1.25em
Line-height: 32px / 2em
- Weight: Light / 300
+ Weight: Medium / 500
Letter-spacing: 0px
@@ -498,7 +498,7 @@ Expressive type is reserved for use in editorial and digital marketing experienc
Typeface: Work Sans
Size: 18px / 1.25em
Line-height: 24px / 1.5em
-
Weight: Light / 300
+
Weight: Medium / 500
Letter-spacing: 0px
@@ -512,14 +512,24 @@ Expressive type is reserved for use in editorial and digital marketing experienc
This is used for layout headings and component titles
-
+
+
+ Heading / 2X-Small
+
+
Typeface: Work Sans
+
Size: 18px / 1.125em
+
Line-height: 24px / 1.5em
+
Weight: Medium / 500
+
Letter-spacing: .32px
+
+
Heading / 2X-Small
Typeface: Work Sans
Size: 16px / 1em
Line-height: 24px / 1.5em
-
Weight: Bold / 700
+
Weight: Medium / 500
Letter-spacing: .32px
diff --git a/website/react-magma-landing/CHANGELOG.md b/website/react-magma-landing/CHANGELOG.md
index df96eab5d..1289b92e0 100644
--- a/website/react-magma-landing/CHANGELOG.md
+++ b/website/react-magma-landing/CHANGELOG.md
@@ -1,5 +1,11 @@
# Change Log
+## 1.1.3-next.0
+
+### Patch Changes
+
+- 52d024ada: build(deps-dev): bump axios from 0.21.1 to 1.6.0
+
## 1.1.2
### Patch Changes
diff --git a/website/react-magma-landing/package.json b/website/react-magma-landing/package.json
index 624fb2e85..934bd7a2c 100644
--- a/website/react-magma-landing/package.json
+++ b/website/react-magma-landing/package.json
@@ -1,6 +1,6 @@
{
"name": "react-magma-landing",
- "version": "1.1.2",
+ "version": "1.1.3-next.0",
"description": "",
"main": "index.js",
"scripts": {
@@ -11,7 +11,7 @@
"keywords": [],
"license": "MIT",
"devDependencies": {
- "axios": "^0.21.1",
+ "axios": "^1.6.0",
"copy": "^0.3.2",
"ejs": "^3.1.5",
"mkdirp": "^1.0.4",