@hig/banner
Advanced tools
Comparing version 0.2.0-alpha.a6b0e91c to 0.2.0-alpha.a8872f53
{ | ||
"name": "@hig/banner", | ||
"version": "0.2.0-alpha.a6b0e91c", | ||
"version": "0.2.0-alpha.a8872f53", | ||
"description": "HIG Banner", | ||
@@ -11,4 +11,5 @@ "author": "Autodesk Inc.", | ||
"devDependencies": { | ||
"@hig/scripts": "0.2.0-alpha.a6b0e91c", | ||
"@hig/styles": "0.1.0-alpha.a6b0e91c" | ||
"@hig/eslint-config": "0.2.0-alpha.a8872f53", | ||
"@hig/scripts": "0.2.0-alpha.a8872f53", | ||
"@hig/styles": "0.1.0-alpha.a8872f53" | ||
}, | ||
@@ -20,7 +21,20 @@ "peerDependencies": { | ||
"scripts": { | ||
"build": "hig-scripts-build" | ||
"build": "hig-scripts-build", | ||
"lint": "eslint ./src/**/*" | ||
}, | ||
"dependencies": { | ||
"hig-react": "0.29.0-alpha.a6b0e91c" | ||
} | ||
"@hig/icon": "0.1.0-alpha.a8872f53", | ||
"@hig/icon-button": "0.1.0-alpha.a8872f53", | ||
"@hig/icons": "0.1.0-alpha.a8872f53", | ||
"@hig/themes": "0.1.0-alpha.a8872f53", | ||
"@hig/typography": "0.1.0-alpha.a8872f53" | ||
}, | ||
"eslintConfig": { | ||
"extends": "@hig" | ||
}, | ||
"eslintIgnore": [ | ||
"*.scss", | ||
"*.json", | ||
"*.js.snap" | ||
] | ||
} |
@@ -5,7 +5,33 @@ import React from "react"; | ||
import { action } from "@storybook/addon-actions"; | ||
import { text, select } from "@storybook/addon-knobs/react"; | ||
import { text, select, boolean } from "@storybook/addon-knobs/react"; | ||
import { withInfo } from "@storybook/addon-info"; | ||
import { makeSelectOptions, translate as t } from "@hig/storybook/utils"; | ||
import { Button, RichText } from "hig-react"; | ||
import readme from "../../README.md"; | ||
import { Button } from "hig-react"; | ||
import Banner from "../Banner"; | ||
import * as languages from "./i18n"; | ||
const typeOptions = makeSelectOptions(Banner.types); | ||
const placementOptions = makeSelectOptions(Banner.placements); | ||
const knobGroupIds = { | ||
basic: "Basic", | ||
animation: "Animation", | ||
a11y: "Accessibility", | ||
actions: "Actions", | ||
i18n: "i18n" | ||
}; | ||
const knobLabels = { | ||
type: "Style", | ||
children: "Message", | ||
placement: "Placement", | ||
isVisible: "Visible", | ||
label: "Label", | ||
dismissButtonTitle: "Dismiss title", | ||
onDismiss: "Banner dismissed", | ||
language: "Language" | ||
}; | ||
function getBannerKnobs(props) { | ||
@@ -15,4 +41,5 @@ const { | ||
placement, | ||
children, | ||
isVisible = true, | ||
label, | ||
message, | ||
dismissButtonTitle, | ||
@@ -24,43 +51,52 @@ onDismiss, | ||
return { | ||
type: select("Type", Banner.AVAILABLE_TYPES, type), | ||
placement: select("Placement", Banner.AVAILABLE_PLACEMENTS, placement), | ||
label: text("Label", label), | ||
message: text("Message", message), | ||
dismissButtonTitle: text("Dismiss title", dismissButtonTitle), | ||
onDismiss: action("Banner dismissed", onDismiss), | ||
labelId: "unique-id", | ||
isVisible: true, | ||
...otherProps | ||
...otherProps, | ||
type: select(knobLabels.type, typeOptions, type, knobGroupIds.basic), | ||
children: text(knobLabels.children, children, knobGroupIds.basic), | ||
placement: select( | ||
knobLabels.placement, | ||
placementOptions, | ||
placement, | ||
knobGroupIds.animation | ||
), | ||
isVisible: boolean(knobLabels.isVisible, isVisible, knobGroupIds.animation), | ||
label: text(knobLabels.label, label, knobLabels.a11y), | ||
dismissButtonTitle: text( | ||
knobLabels.dismissButtonTitle, | ||
dismissButtonTitle, | ||
knobGroupIds.a11y | ||
), | ||
onDismiss: action(knobLabels.onDismiss, onDismiss, knobGroupIds.actions) | ||
}; | ||
} | ||
function BannerDemo({ children, ...props }) { | ||
return ( | ||
<div style={{ marginBottom: "15px" }}> | ||
<Banner {...getBannerKnobs(props)}>{children}</Banner> | ||
</div> | ||
); | ||
} | ||
const bannerStories = storiesOf("Banner", module); | ||
function BannerStory({ props }) { | ||
return <BannerDemo {...props} />; | ||
} | ||
bannerStories.add( | ||
"default", | ||
withInfo({ | ||
propTables: [Banner], | ||
text: <RichText dangerouslySetInnerHTML={{ __html: readme }} /> | ||
})(() => { | ||
const { children, ...otherProps } = getBannerKnobs({}); | ||
return <Banner {...otherProps}>{children}</Banner>; | ||
}) | ||
); | ||
const bannerStories = storiesOf("Banner", module); | ||
const stories = [ | ||
{ | ||
description: "default", | ||
props: {} | ||
}, | ||
{ | ||
description: "verbose, with interactions", | ||
props: { | ||
bannerStories.add( | ||
"verbose, with interactions", | ||
withInfo({ | ||
propTables: [Banner], | ||
text: <RichText dangerouslySetInnerHTML={{ __html: readme }} /> | ||
})(() => { | ||
const chosenLanguage = select( | ||
knobLabels.language, | ||
languages.languageOptions, | ||
"en", | ||
knobGroupIds.i18n | ||
); | ||
const props = { | ||
type: Banner.types.WARNING, | ||
label: "PROCESS COMPLETE", | ||
// eslint-disable-next-line max-len | ||
message: | ||
"Changes have been made to you document. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.", | ||
children: t(languages, chosenLanguage, "BANNER_MESSAGE"), | ||
/** @todo Cleanup/refactor */ | ||
children: ({ isWrappingActions }) => ( | ||
actions: ({ isWrappingActions }) => ( | ||
<Banner.Interactions isWrappingActions={isWrappingActions}> | ||
@@ -72,3 +108,6 @@ <Banner.Action> | ||
width={isWrappingActions ? "grow" : "shrink"} | ||
title={text("Resolve text", "Accept Changes")} | ||
title={text( | ||
"Resolve text", | ||
t(languages, chosenLanguage, "BANNER_RESOLVE_BUTTON_TEXT") | ||
)} | ||
/> | ||
@@ -81,3 +120,6 @@ </Banner.Action> | ||
width={isWrappingActions ? "grow" : "shrink"} | ||
title={text("Reject text", "Reject Changes")} | ||
title={text( | ||
"Reject text", | ||
t(languages, chosenLanguage, "BANNER_REJECT_BUTTON_TEXT") | ||
)} | ||
/> | ||
@@ -87,8 +129,6 @@ </Banner.Action> | ||
) | ||
} | ||
} | ||
]; | ||
stories.forEach(({ description, props }) => { | ||
bannerStories.add(description, () => <BannerStory props={props} />); | ||
}); | ||
}; | ||
const { children, ...otherProps } = getBannerKnobs(props); | ||
return <Banner {...otherProps}>{children}</Banner>; | ||
}) | ||
); |
@@ -17,6 +17,6 @@ import React, { Component } from "react"; | ||
* @property {string} [label] | ||
* @property {string} [message] | ||
* @property {string} [labelledBy] | ||
* @property {any} [actions] | ||
* @property {string} [dismissButtonTitle] | ||
* @property {Function} [onDismiss] | ||
* @property {string} [labelId] | ||
* @property {boolean} [isVisible] | ||
@@ -44,4 +44,6 @@ * @property {any} [children] | ||
label: PropTypes.string, | ||
/** The displayed message */ | ||
message: PropTypes.string, | ||
/** The ID used for ARIA labeling */ | ||
labelledBy: PropTypes.string, | ||
/** Banner actions; Any JSX, or a render prop function */ | ||
actions: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), | ||
/** Accessibility text for the dismiss button */ | ||
@@ -51,8 +53,6 @@ dismissButtonTitle: PropTypes.string, | ||
onDismiss: PropTypes.func, | ||
/** The ID used for ARIA labeling */ | ||
labelId: PropTypes.string, | ||
/** Animation; Determines the visibility of the banner */ | ||
isVisible: PropTypes.bool, | ||
/** Banner actions; Any JSX, or a render prop function */ | ||
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]) | ||
/** The displayed message */ | ||
children: PropTypes.string | ||
}; | ||
@@ -74,3 +74,3 @@ | ||
render() { | ||
const { isVisible, children: actions } = this.props; | ||
const { isVisible, actions } = this.props; | ||
const { renderPresenter } = this; | ||
@@ -77,0 +77,0 @@ |
@@ -7,21 +7,22 @@ import { mount } from "enzyme"; | ||
describe("banner/Banner", () => { | ||
describe("Action", () => { | ||
it("exposes the `Action` component", () => { | ||
expect(Banner).toHaveProperty("Action", expect.any(Function)); | ||
}); | ||
}); | ||
const exposedComponents = ["Action", "Interactions", "Presenter"]; | ||
const componentMatcher = expect.any(Function); | ||
describe("Interactions", () => { | ||
it("exposes the `Interactions` component", () => { | ||
expect(Banner).toHaveProperty("Interactions", expect.any(Function)); | ||
exposedComponents.forEach(componentName => { | ||
describe(componentName, () => { | ||
it(`exposes the \`${componentName}\` component`, () => { | ||
expect(Banner).toHaveProperty(componentName, componentMatcher); | ||
}); | ||
}); | ||
}); | ||
describe("Presenter", () => { | ||
it("exposes the `Presenter` component", () => { | ||
expect(Banner).toHaveProperty("Presenter", expect.any(Function)); | ||
}); | ||
}); | ||
describe("rendering", () => { | ||
const renderedComponents = [ | ||
"BannerAnimator", | ||
"BannerContainer", | ||
"BannerPresenter" | ||
]; | ||
describe("rendering", () => { | ||
let wrapper; | ||
beforeAll(() => { | ||
@@ -31,2 +32,6 @@ window.requestAnimationFrame = jest.fn(); | ||
beforeEach(() => { | ||
wrapper = mount(<Banner />); | ||
}); | ||
afterAll(() => { | ||
@@ -36,20 +41,10 @@ delete window.requestAnimationFrame; | ||
it("renders the `BannerAnimator`", () => { | ||
const wrapper = mount(<Banner />); | ||
expect(wrapper.find("BannerAnimator")).toBePresent(); | ||
renderedComponents.forEach(componentName => { | ||
describe(componentName, () => { | ||
it(`renders a \`${componentName}\` component`, () => { | ||
expect(wrapper.find(componentName)).toBePresent(); | ||
}); | ||
}); | ||
}); | ||
it("renders the `BannerContainer`", () => { | ||
const wrapper = mount(<Banner />); | ||
expect(wrapper.find("BannerContainer")).toBePresent(); | ||
}); | ||
it("renders the `BannerPresenter`", () => { | ||
const wrapper = mount(<Banner />); | ||
expect(wrapper.find("BannerPresenter")).toBePresent(); | ||
}); | ||
}); | ||
}); |
@@ -193,3 +193,3 @@ import { Component } from "react"; | ||
refInteractionsWrapper, | ||
children: this.renderActions() | ||
actions: this.renderActions() | ||
}; | ||
@@ -196,0 +196,0 @@ } |
@@ -28,3 +28,3 @@ import { shallow } from "enzyme"; | ||
expect(presenterBag).toMatchObject({ | ||
children: "foobar", | ||
actions: "foobar", | ||
isWrappingContent: false, | ||
@@ -31,0 +31,0 @@ refContent: expect.any(Function), |
@@ -5,3 +5,2 @@ import React from "react"; | ||
import { types, AVAILABLE_TYPES } from "../types"; | ||
import { placements, AVAILABLE_PLACEMENTS } from "../placements"; | ||
@@ -11,5 +10,3 @@ import { | ||
DismissButton, | ||
Icon, | ||
InteractionsWrapper, | ||
Label, | ||
Message, | ||
@@ -19,2 +16,3 @@ Notification, | ||
} from "./presenters"; | ||
import IconBackground from "../presenters/IconBackground"; | ||
@@ -24,8 +22,7 @@ /** | ||
* @property {string} [type] | ||
* @property {string} [placement] | ||
* @property {string} [label] | ||
* @property {string} [message] | ||
* @property {string} [labelledBy] | ||
* @property {any} [actions] | ||
* @property {string} [dismissButtonTitle] | ||
* @property {Function} [onDismiss] | ||
* @property {string} [labelId] | ||
* @property {boolean} [isWrappingContent] | ||
@@ -46,8 +43,7 @@ * @property {function(HTMLDivElement): any} [refContent] | ||
type, | ||
placement, | ||
label, | ||
message, | ||
labelledBy, | ||
actions, | ||
dismissButtonTitle, | ||
onDismiss, | ||
labelId, | ||
isWrappingContent, | ||
@@ -57,8 +53,6 @@ refContent, | ||
refInteractionsWrapper, | ||
children | ||
children: message | ||
} = props; | ||
const hasLabel = !!label; | ||
const hasActions = React.Children.count(children) > 0; | ||
const wrapperLabelledBy = hasLabel ? labelId : undefined; | ||
const hasActions = React.Children.count(actions) > 0; | ||
@@ -68,11 +62,10 @@ return ( | ||
type={type} | ||
placement={placement} | ||
hasActions={hasActions} | ||
isWrappingContent={isWrappingContent} | ||
labelledBy={wrapperLabelledBy} | ||
label={label} | ||
labelledBy={labelledBy} | ||
> | ||
<Icon type={type} /> | ||
<IconBackground type={type} /> | ||
<Content innerRef={refContent}> | ||
<Notification innerRef={refNotification}> | ||
{hasLabel ? <Label id={labelId}>{label}</Label> : null} | ||
<Message>{message}</Message> | ||
@@ -82,3 +75,3 @@ </Notification> | ||
<InteractionsWrapper innerRef={refInteractionsWrapper}> | ||
{children} | ||
{actions} | ||
</InteractionsWrapper> | ||
@@ -95,6 +88,5 @@ ) : null} | ||
type: types.PRIMARY, | ||
placement: placements.STANDARD, | ||
message: "Message", | ||
dismissButtonTitle: "Dismiss", | ||
isWrappingContent: false | ||
isWrappingContent: false, | ||
children: "Message" | ||
}; | ||
@@ -105,8 +97,8 @@ | ||
type: PropTypes.oneOf(AVAILABLE_TYPES), | ||
/** Determines the intended placement of banner */ | ||
placement: PropTypes.oneOf(AVAILABLE_PLACEMENTS), | ||
/** The label of the message displayed */ | ||
label: PropTypes.string, | ||
/** The displayed message */ | ||
message: PropTypes.string, | ||
/** The ID used for ARIA labeling */ | ||
labelledBy: PropTypes.string, | ||
/** Banner actions */ | ||
actions: PropTypes.node, | ||
/** Accessibility text for the dismiss button */ | ||
@@ -116,4 +108,2 @@ dismissButtonTitle: PropTypes.string, | ||
onDismiss: PropTypes.func, | ||
/** The ID used for ARIA labeling */ | ||
labelId: PropTypes.string, | ||
/** Determines whether the banner content wraps */ | ||
@@ -127,4 +117,4 @@ isWrappingContent: PropTypes.bool, | ||
refInteractionsWrapper: PropTypes.func, | ||
/** Banner actions */ | ||
/** The displayed message */ | ||
children: PropTypes.node | ||
}; |
import React from "react"; | ||
import renderer from "react-test-renderer"; | ||
import { placements } from "../placements"; | ||
import { types } from "../types"; | ||
@@ -19,23 +18,22 @@ import BannerPresenter from "./BannerPresenter"; | ||
label: "HELLO", | ||
message: "World" | ||
children: "World" | ||
} | ||
}, | ||
{ | ||
description: "renders with a string as children", | ||
description: "renders with a string as actions", | ||
props: { | ||
placement: placements.TOP, | ||
children: "foobar" | ||
actions: "foobar" | ||
} | ||
}, | ||
{ | ||
description: "renders with a node as children", | ||
description: "renders with a node as actions", | ||
props: { | ||
dismissButtonTitle: "boom", | ||
children: <span>foo</span> | ||
actions: <span>foo</span> | ||
} | ||
}, | ||
{ | ||
description: "renders with a fragment as children", | ||
description: "renders with a fragment as actions", | ||
props: { | ||
children: [<span key="0">bar</span>, <div key="1">baz</div>] | ||
actions: [<span key="0">bar</span>, <div key="1">baz</div>] | ||
} | ||
@@ -42,0 +40,0 @@ } |
@@ -6,7 +6,10 @@ /* eslint-disable react/prop-types */ | ||
import { Icon as BasicIcon, IconButton, Text } from "hig-react"; | ||
import { names as iconNames } from "@hig/icon"; | ||
import IconButton, { types as iconButtonTypes } from "@hig/icon-button"; | ||
import { Text } from "@hig/typography"; | ||
import { ThemeContext } from "@hig/themes"; | ||
import "./banner-presenter.scss"; | ||
import { placements } from "../placements"; | ||
import { types } from "../types"; | ||
import classNames from "../presenters/classNames"; | ||
@@ -16,32 +19,3 @@ /** @todo Reference from constant on `Text` component */ | ||
const { types: iconButtonTypes } = IconButton; | ||
const { names: iconNames, sizes: iconSizes } = BasicIcon; | ||
/** @type {Object.<string, string>} */ | ||
const classNames = Object.freeze({ | ||
action: "hig__banner__action", | ||
actionsWrapper: "hig__banner__action-wrapper", | ||
content: "hig__banner__content", | ||
dismissButton: "hig__banner__dismiss-button", | ||
iconBackground: "hig__banner__icon-background", | ||
interactionsWrapper: "hig__banner__interactions-wrapper", | ||
notification: "hig__banner__notification", | ||
wrapper: "hig__banner", | ||
wrapperBottom: "hig__banner--bottom", | ||
wrapperUrgent: "hig__banner--urgent", | ||
wrapperInteractive: "hig__banner--interactive", | ||
wrapperPrimary: "hig__banner--primary", | ||
wrapperComplete: "hig__banner--complete", | ||
wrapperTop: "hig__banner--top", | ||
wrapperWarning: "hig__banner--warning", | ||
wrapperWrapContent: "hig__banner--wrap-content" | ||
}); | ||
/** @type {Object.<string, string>} */ | ||
const wrapperModifiersByPlacement = { | ||
[placements.BOTTOM]: classNames.wrapperBottom, | ||
[placements.TOP]: classNames.wrapperTop | ||
}; | ||
/** @type {Object.<string, string>} */ | ||
const wrapperModifiersByType = { | ||
@@ -54,10 +28,2 @@ [types.PRIMARY]: classNames.wrapperPrimary, | ||
/** @type {Object.<string, string>} */ | ||
const iconNamesByType = { | ||
[types.PRIMARY]: iconNames.INFO, | ||
[types.COMPLETE]: iconNames.COMPLETE, | ||
[types.WARNING]: iconNames.ISSUE, | ||
[types.URGENT]: iconNames.ERROR | ||
}; | ||
/** | ||
@@ -72,3 +38,2 @@ * @typedef {Object} StyledProps | ||
* @property {string} type | ||
* @property {string} placement | ||
* @property {boolean} hasActions | ||
@@ -87,4 +52,4 @@ * @property {string | undefined} [labelledBy] | ||
type, | ||
placement, | ||
hasActions, | ||
label, | ||
labelledBy, | ||
@@ -95,14 +60,25 @@ isWrappingContent, | ||
const classes = cx( | ||
classNames.wrapper, | ||
wrapperModifiersByType[type], | ||
wrapperModifiersByPlacement[placement], | ||
hasActions ? classNames.wrapperInteractive : undefined, | ||
isWrappingContent ? classNames.wrapperWrapContent : undefined | ||
); | ||
function classes(themeClass) { | ||
return cx( | ||
classNames.wrapper, | ||
wrapperModifiersByType[type], | ||
hasActions ? classNames.wrapperInteractive : undefined, | ||
isWrappingContent ? classNames.wrapperWrapContent : undefined, | ||
themeClass | ||
); | ||
} | ||
return ( | ||
<div role="alert" aria-labelledby={labelledBy} className={classes}> | ||
{children} | ||
</div> | ||
<ThemeContext.Consumer> | ||
{({ themeClass }) => ( | ||
<div | ||
role="alert" | ||
aria-label={label} | ||
aria-labelledby={labelledBy} | ||
className={classes(themeClass)} | ||
> | ||
{children} | ||
</div> | ||
)} | ||
</ThemeContext.Consumer> | ||
); | ||
@@ -148,19 +124,2 @@ } | ||
/** | ||
* @typedef {Object} IconProps | ||
* @property {string} type | ||
*/ | ||
/** | ||
* @param {IconProps} props | ||
* @returns {JSX.Element} | ||
*/ | ||
export function Icon({ type }) { | ||
return ( | ||
<figure className={classNames.iconBackground}> | ||
<BasicIcon name={iconNamesByType[type]} size={iconSizes.MEDIUM} /> | ||
</figure> | ||
); | ||
} | ||
/** | ||
* @param {StyledProps} props | ||
@@ -178,16 +137,2 @@ * @returns {JSX.Element} | ||
/** | ||
* @typedef {Object} LabelProps | ||
* @property {string} [id] | ||
* @property {any} [children] | ||
*/ | ||
/** | ||
* @param {LabelProps} props | ||
* @returns {JSX.Element} | ||
*/ | ||
export function Label({ id, children }) { | ||
return <Text color={TEXT_COLOR} id={id}>{`${children}: `}</Text>; | ||
} | ||
/** | ||
* @param {StyledProps} props | ||
@@ -201,6 +146,2 @@ * @returns {JSX.Element} | ||
if (typeof children === "function") { | ||
return children(); | ||
} | ||
return children; | ||
@@ -207,0 +148,0 @@ } |
import "./external.scss"; | ||
export { default } from "./Banner"; | ||
@@ -3,0 +4,0 @@ export { default as BannerAction } from "./BannerAction"; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
127039
45
3197
1
50
7
3
1
+ Added@hig/icon@0.1.0-alpha.a8872f53(transitive)
+ Added@hig/icon-button@0.1.0-alpha.a8872f53(transitive)
+ Added@hig/icons@0.1.0-alpha.a8872f53(transitive)
+ Added@hig/themes@0.1.0-alpha.a8872f53(transitive)
+ Added@hig/typography@0.1.0-alpha.a8872f53(transitive)
- Removedhig-react@0.29.0-alpha.a6b0e91c
- Removed@babel/runtime@7.25.6(transitive)
- Removeddom-helpers@3.4.0(transitive)
- Removedhig-interface@0.2.0-alpha.a6b0e91c(transitive)
- Removedhig-react@0.29.0-alpha.a6b0e91c(transitive)
- Removedhig-vanilla@0.2.0-alpha.a6b0e91c(transitive)
- Removedreact@18.3.1(transitive)
- Removedreact-dom@15.7.018.3.1(transitive)
- Removedreact-flip-move@3.0.5(transitive)
- Removedreact-lifecycles-compat@3.0.4(transitive)
- Removedreact-transition-group@2.9.0(transitive)
- Removedregenerator-runtime@0.14.1(transitive)
- Removedscheduler@0.23.2(transitive)