UNPKG

@kiwicom/orbit-components

Version:

Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com's products.

364 lines (362 loc) 18.6 kB
"use strict"; "use client"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; exports.__esModule = true; exports.default = exports.AlertButton = void 0; var React = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _InformationCircle = _interopRequireDefault(require("../icons/InformationCircle")); var _AlertCircle = _interopRequireDefault(require("../icons/AlertCircle")); var _AlertOctagon = _interopRequireDefault(require("../icons/AlertOctagon")); var _CheckCircle = _interopRequireDefault(require("../icons/CheckCircle")); var _Close = _interopRequireDefault(require("../icons/Close")); var _ButtonLink = _interopRequireDefault(require("../ButtonLink")); var _consts = require("./consts"); var _tailwind = require("../common/tailwind"); var _twClasses = require("../TextLink/helpers/twClasses"); var _AlertButton = _interopRequireDefault(require("./AlertButton")); exports.AlertButton = _AlertButton.default; const COLORS = { info: "bg-blue-light border border-alert-info", success: "bg-green-light border border-alert-success", warning: "bg-orange-light border border-alert-warning", critical: "bg-red-light border border-alert-critical" }; const ICON_COLOR = { info: "text-blue-normal", success: "text-green-normal", warning: "text-orange-normal", critical: "text-red-normal" }; const StyledIcon = ({ icon, type }) => { // Icon should be boolean and TRUE if (typeof icon === "boolean" && icon) { if (type === _consts.TYPE_OPTIONS.INFO) { return /*#__PURE__*/React.createElement(_InformationCircle.default, { size: "small", ariaHidden: true }); } if (type === _consts.TYPE_OPTIONS.SUCCESS) { return /*#__PURE__*/React.createElement(_CheckCircle.default, { size: "small", ariaHidden: true }); } if (type === _consts.TYPE_OPTIONS.WARNING) { return /*#__PURE__*/React.createElement(_AlertCircle.default, { size: "small", ariaHidden: true }); } if (type === _consts.TYPE_OPTIONS.CRITICAL) { return /*#__PURE__*/React.createElement(_AlertOctagon.default, { size: "small", ariaHidden: true }); } } if ( /*#__PURE__*/React.isValidElement(icon) && typeof icon !== "boolean") { // @ts-expect-error TODO return /*#__PURE__*/React.cloneElement(icon, { size: "small" }); } return /*#__PURE__*/React.createElement(React.Fragment, null, icon); }; const ContentWrapper = ({ type, inlineActions, children }) => { return /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("min-h-icon-medium flex items-center", !inlineActions && "w-full", "[&_.orbit-list-item]:text-ink-dark [&_.orbit-text]:text-ink-dark [&_.orbit-heading]:text-ink-dark", ..._twClasses.alertDescendantClasses[type]) }, children); }; const AlertCloseButton = ({ hasChildren, dataTest, onClick, labelClose, icon }) => { return /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("end-0", hasChildren && "top-0") }, /*#__PURE__*/React.createElement(_ButtonLink.default, { dataTest: dataTest, onClick: onClick, size: "small", iconLeft: icon, type: "secondary", title: labelClose })); }; /** * @orbit-doc-start * README * ---------- * # Alert * * To implement Alert component into your project you'll need to add the import: * * ```jsx * import Alert from "@kiwicom/orbit-components/lib/Alert"; * ``` * * After adding import into your project you can use it simply like: * * ```jsx * <Alert>Hello World!</Alert> * ``` * * ## Props * * The table below contains all types of the props available in Alert component. * * | Name | Type | Default | Description | * | :------------ | :------------------------------ | :------- | :------------------------------------------------------------------------------------- | * | children | `React.Node` | | The content of the Alert. | * | closable | `boolean` | `false` | If `true`, the Close icon will be displayed. [See Functional specs](#functional-specs) | * | dataTest | `string` | | Optional prop for testing purposes. | * | id | `string` | | Set `id` for `Alert`. | * | icon | `React.Element<any> \| boolean` | | The displayed icon. [See Functional specs](#functional-specs) | * | inlineActions | `React.Node` | | Renders action to a right side of a Alert. [See Functional specs](#functional-specs) | * | onClose | `() => void \| Promise` | | Function for handling Alert onClose. | * | spaceAfter | `enum` | | Additional `margin-bottom` after component. | * | title | `string` | | The title of the Alert. | * | **type** | [`enum`](#enum) | `"info"` | The type of Alert. | * | suppressed | `boolean` | | If `suppressed` is on, Alert will not have colored background. | * | labelClose | `string` | | The label of the close button. **Required** when `closable` is `true`. | * * ### enum * * | type | spaceAfter | * | :----------- | :----------- | * | `"info"` | `"none"` | * | `"success"` | `"smallest"` | * | `"warning"` | `"small"` | * | `"critical"` | `"normal"` | * | | `"medium"` | * | | `"large"` | * | | `"largest"` | * * ## Functional specs * * - By passing the `closable` prop into Alert, you will be able to handle `onClose` function and Close icon will be displayed. When `closable` is `true`, the `labelClose` prop is required for accessibility. Also, if you want to select the Close Button element for testing purposes, use [data-test="AlertCloseButton"] selector. * * - When the Alert has a `title` prop, if you pass an `icon` prop as `true`, the Alert will have its own icon based on the selected `type`. If you want to use a different icon, just pass it to the `icon` prop as a `React.Element`. Alerts without a `title` or with a `title` but without an `icon` prop don't have an icon. * * - Passing a `inlineActions` will cause `children` to be ignored. `inlineActions` should be used for displaying buttons inside short alerts which only have a `title`. * * ## Subcomponents * * ### AlertButton * * To implement AlertButton component into your project you'll need to add the import: * * ```jsx * import AlertButton from "@kiwicom/orbit-components/lib/Alert/AlertButton"; * // or * import { AlertButton } from "@kiwicom/orbit-components/lib/Alert"; * ``` * * After adding import into your project you can use it simply like: * * ```jsx * <AlertButton type="info">Hello World!</AlertButton> * ``` * * ## Props * * Table below contains all types of the props available in AlertButton component. * * | Name | Type | Default | Description | * | :----------- | :------------------------- | :---------- | :---------------------------------------------------------------------------------- | * | ariaControls | `string` | | Id of the element the button controls. | * | ariaExpanded | `boolean` | | Tells screen reader the controlled element from `ariaControls` is expanded | * | asComponent | `string \| React.Element` | `"button"` | The component used for the root node. | * | fullWidth | `boolean` | `false` | If `true`, the AlertButton grows to the full width of its container. | * | circled | `boolean` | `false` | If `true`, the AlertButton is circular. | * | children | `React.Node` | | The content of the AlertButton. | * | dataTest | `string` | | Optional prop for testing purposes. | * | disabled | `boolean` | `false` | If `true`, the AlertButton is disabled. | * | external | `boolean` | `false` | If `true`, the AlertButton opens link in a new tab. | * | href | `string` | | The URL of the link to open when AlertButton is clicked. | * | iconLeft | `React.Node` | | The displayed icon on the left. | * | iconRight | `React.Node` | | The displayed icon on the right. | * | loading | `boolean` | `false` | If `true`, the loading glyph is displayed. | * | onClick | `event => void \| Promise` | | Function for handling onClick event. | * | ref | `func` | | Prop for forwarded ref of the AlertButton. | * | role | `string` | | Specifies the role of an element. | * | spaceAfter | `enum` | | Additional `margin-bottom` after component. | * | submit | `boolean` | `false` | If `true`, the Button has the `type="submit"` attribute, otherwise `type="button"`. | * | tabIndex | `string \| number` | | Specifies the tab order of an element. | * | title | `string` | | Adds `aria-label`. | * | **type** | [`enum`](#button-enum) | `"primary"` | The type of AlertButton. | * | width | `string` | | The width of the AlertButton. Can be any string - `100px`, `20%`. | * * ### Button enum * * | type | spaceAfter | * | :----------------- | :----------- | * | `"info"` | `"none"` | * | `"success"` | `"smallest"` | * | `"warning"` | `"small"` | * | `"critical"` | `"normal"` | * | `"infoSubtle"` | `"medium"` | * | `"successSubtle"` | `"large"` | * | `"warningSubtle"` | `"largest"` | * | `"criticalSubtle"` | * * * Accessibility * ------------- * # Accessibility * * ## Alert * * The Alert component has been designed with accessibility in mind. * * ### Accessibility props * * The following props are available to improve the accessibility of your Alert component: * * | Prop | Type | Description | * | :--------- | :------- | :----------------------------------------------------------------------- | * | labelClose | `string` | Defines accessible text for the close button when the alert is closable. | * * When the `closable` prop is set to `true`, the `labelClose` prop is required. It provides the text that screen readers will announce when focusing on the close button, helping users understand its purpose. * * The `labelClose` text should be properly translated. * * ### Best practices * * - When using the `icon` prop, follow the accessibility guidelines documented in the Icon component's accessibility documentation to ensure that the icon is properly accessible or visually hidden from screen readers when it is purely decorative. * * ### Code examples * * #### Using labelClose with closable alert * * ```jsx * <Alert * type="info" * title="Notification" * closable * labelClose="Close notification" // Should be a translated string * onClose={() => { * // handle close action * }} * > * This is an important update for your upcoming flight. * </Alert> * ``` * * In this example, screen readers would announce "Close notification" when focusing on the close button. * * #### Non-closable alert (no accessibility props required) * * ```jsx * <Alert type="success" title="Success"> * Your booking has been confirmed. * </Alert> * ``` * * In this example, the alert doesn't require additional accessibility props as it doesn't have interactive elements that need labels. * * ## AlertButton * * The AlertButton component also includes several accessibility features: * * ### Accessibility props * * | Prop | Type | Description | * | :------------- | :-------- | :----------------------------------------------------------------------------------------------- | * | title | `string` | Adds `aria-label` to the button, providing a description for screen readers. | * | ariaControls | `string` | Identifies the element controlled by the button, establishing a relationship for screen readers. | * | ariaExpanded | `boolean` | Indicates to screen readers whether the controlled element is expanded. | * | ariaLabelledby | `string` | References the ID of an element that labels the button. | * * ### Best practices * * - The `title` prop should be used when the button's purpose isn't clear from its content alone or when additional context would help screen reader users. * - When the AlertButton controls the visibility of another element (like a collapsible section), use `ariaControls` with the ID of that element and `ariaExpanded` to indicate its state. * - Always translate accessibility-related text to match the user's language. * - Use the `asComponent` prop to change the rendered element when the AlertButton is used inside another interactive element (like another button or a link). This helps avoid accessibility violations from nesting interactive elements, which can confuse screen readers and keyboard navigation. * - When using `iconLeft` or `iconRight` props, follow the accessibility guidelines documented in the Icon component's accessibility documentation to ensure that icons are properly accessible or visually hidden from screen readers when they are purely decorative. * * You can find additional accessibility guidance in the Button accessibility documentation. * * ### Code example * * ```jsx * <Alert type="warning" title="Flight delay information"> * <p>Your flight has been delayed by 2 hours.</p> * <AlertButton * type="warning" * ariaControls="details-panel" * ariaExpanded={detailsVisible} * onClick={() => setDetailsVisible(!detailsVisible)} * > * {detailsVisible ? "Hide details" : "Show details"} * </AlertButton> * <div id="details-panel" style={{ display: detailsVisible ? "block" : "none" }}> * Detailed information about the delay... * </div> * </Alert> * ``` * * In this example, screen readers would announce the button text along with information about what element it controls and whether that element is currently expanded. * * * @orbit-doc-end */ const Alert = props => { const { type = _consts.TYPE_OPTIONS.INFO, title, icon, closable, onClose, children, dataTest, id, spaceAfter, suppressed, inlineActions, labelClose } = props; return /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("orbit-alert", "rounded-300 text-ink-dark font-base text-normal p-300 relative box-border flex w-full leading-normal", Boolean(inlineActions) && "items-center", suppressed ? "bg-cloud-light" : COLORS[type], spaceAfter && _tailwind.spaceAfterClasses[spaceAfter]), id: id, "data-test": dataTest }, icon && /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("me-200 m-0 shrink-0 leading-none", Boolean(inlineActions) && "lm:mt-150 flex items-center self-baseline", ICON_COLOR[type], "tb:me-200 tb:[&_svg]:size-icon-medium") }, /*#__PURE__*/React.createElement(StyledIcon, { type: type, icon: icon })), /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("flex flex-1", title && inlineActions ? "flex-row" : "flex-col", !title && "items-center", Boolean(inlineActions) && "justify-between") }, title && /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("text-ink-dark min-h-icon-medium flex items-center font-bold", !!children && (inlineActions ? "mb-0" : "mb-100"), Boolean(inlineActions) && "grow basis-0") }, title), children && !inlineActions && /*#__PURE__*/React.createElement(ContentWrapper, { type: type }, children), inlineActions && /*#__PURE__*/React.createElement(ContentWrapper, { type: type, inlineActions: !!inlineActions }, inlineActions)), closable && /*#__PURE__*/React.createElement(AlertCloseButton, { hasChildren: !!children, dataTest: _consts.CLOSE_BUTTON_DATA_TEST, onClick: onClose, labelClose: labelClose, icon: /*#__PURE__*/React.createElement(_Close.default, { size: "small", color: type, ariaHidden: true }) })); }; var _default = exports.default = Alert;