UNPKG

@amsterdam/design-system-react

Version:

All React components from the Amsterdam Design System. Use it to compose pages in your website or application.

1,681 lines (1,612 loc) 149 kB
import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import { clsx } from 'clsx'; import { createContext, forwardRef, useContext, useState, useEffect, useId, useRef, useImperativeHandle, startTransition, useMemo } from 'react'; import { ChevronDownIcon, CloseIcon, WarningFillIcon, SuccessFillIcon, ErrorFillIcon, InfoFillIcon, PersonFillIcon, WarningIcon, DocumentIcon, ChevronBackwardIcon, ChevronForwardIcon, ArrowForwardIcon, SearchIcon } from '@amsterdam/design-system-react-icons'; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const KeyboardKeys = { ArrowDown: 'ArrowDown', ArrowLeft: 'ArrowLeft', ArrowRight: 'ArrowRight', ArrowUp: 'ArrowUp', End: 'End', Home: 'Home' }; const FOCUSABLE_ELEMENTS = ['a[href]:not([disabled])', 'button:not([disabled])', 'textarea:not([disabled])', 'input[type="text"]:not([disabled])', 'input[type="radio"]:not([disabled])', 'input[type="checkbox"]:not([disabled])', 'select:not([disabled])']; const useKeyboardFocus = (ref, options) => { const { directChildrenOnly = false, focusableElements = FOCUSABLE_ELEMENTS, horizontally = false, rotating = false } = options; const nextKey = horizontally ? KeyboardKeys.ArrowRight : KeyboardKeys.ArrowDown; const prevKey = horizontally ? KeyboardKeys.ArrowLeft : KeyboardKeys.ArrowUp; const keyDown = e => { if (!ref.current) return; const element = ref.current; const { activeElement } = document; const directChildSelector = directChildrenOnly ? ':scope > ' : ''; const focusableEls = Array.from(element.querySelectorAll(`${directChildSelector}${focusableElements.join(`, ${directChildSelector}`)}`)); const getIndex = el => el && focusableEls.includes(el) ? focusableEls.indexOf(el) : -1; let targetElement; switch (e.key) { case KeyboardKeys.End: targetElement = focusableEls[focusableEls.length - 1]; break; case KeyboardKeys.Home: targetElement = focusableEls[0]; break; case nextKey: targetElement = focusableEls[getIndex(activeElement) + 1] || (rotating ? focusableEls[0] : undefined); break; case prevKey: targetElement = focusableEls[getIndex(activeElement) - 1] || (rotating ? focusableEls[focusableEls.length - 1] : undefined); break; } if (targetElement instanceof HTMLElement) { targetElement.focus(); e.preventDefault(); } }; return { keyDown }; }; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const defaultValues$3 = { // Default value for type safety. // The actual value is always provided via Accordion’s required headingLevel prop. headingLevel: 2 }; const AccordionContext = /*#__PURE__*/createContext(defaultValues$3); /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ function getHeadingTag(level) { switch (level) { case 2: return 'h2'; case 3: return 'h3'; case 4: return 'h4'; // Ensure valid HTML with invalid input outside of TypeScript. default: return 'h1'; } } /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-text-heading--docs Heading docs at Amsterdam Design System} */ const Heading = /*#__PURE__*/forwardRef(({ children, className, color, level, size, ...restProps }, ref) => { const Tag = getHeadingTag(level); const visualLevel = size ? size.slice(-1) : level; return jsx(Tag, { className: clsx('ams-heading', `ams-heading--${visualLevel}`, color && `ams-heading--${color}`, className), ref: ref, ...restProps, children: children }); }); Heading.displayName = 'Heading'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-media-icon--docs Icon docs at Amsterdam Design System} * @see {@link https://designsystem.amsterdam/?path=/docs/brand-assets-icons--docs Icons overview at Amsterdam Design System} */ const Icon = /*#__PURE__*/forwardRef(({ className, color, size, square, svg, ...restProps }, ref) => jsx("span", { className: clsx('ams-icon', color && `ams-icon--${color}`, size && `ams-icon--${size}`, square && 'ams-icon--square', className), hidden // The icon is only shown when the CSS loads, so we hide it by default. : true, ref: ref, ...restProps, children: typeof svg === 'function' ? svg({}) : svg })); Icon.displayName = 'Icon'; const AccordionSection = /*#__PURE__*/forwardRef(({ children, className, defaultExpanded, expanded, label, ...restProps }, ref) => { const { headingLevel, sectionAs } = useContext(AccordionContext); const [isExpanded, setIsExpanded] = useState(defaultExpanded ?? expanded ?? false); useEffect(() => { if (expanded !== undefined) { console.warn('Accordion.Section: The `expanded` prop is deprecated. Use `defaultExpanded` instead.'); } }, []); const SectionTag = sectionAs || 'section'; const id = useId(); const iconSize = `heading-${headingLevel}`; const buttonId = `button-${id}`; const panelId = `panel-${id}`; return jsxs("div", { className: clsx('ams-accordion__section', className), ref: ref, ...restProps, children: [jsx(Heading, { level: headingLevel, children: jsxs("button", { "aria-controls": panelId, "aria-expanded": isExpanded, className: "ams-accordion__button", id: buttonId, onClick: () => setIsExpanded(!isExpanded), type: "button", children: [jsx(Icon, { className: "ams-accordion__icon", size: iconSize, svg: ChevronDownIcon }), label] }) }), jsx(SectionTag, { "aria-labelledby": buttonId, className: clsx('ams-accordion__panel', { 'ams-accordion__panel--expanded': isExpanded }), id: panelId, children: children })] }); }); AccordionSection.displayName = 'Accordion.Section'; const AccordionRoot = /*#__PURE__*/forwardRef(({ children, className, headingLevel, sectionAs = 'section', ...restProps }, ref) => { const innerRef = useRef(null); // use a passed ref if it's there, otherwise use innerRef useImperativeHandle(ref, () => innerRef.current); const { keyDown } = useKeyboardFocus(innerRef, { focusableElements: ['.ams-accordion__button:not([disabled])'], rotating: true }); return jsx(AccordionContext.Provider, { value: { headingLevel: headingLevel, sectionAs: sectionAs }, children: jsx("div", { ...restProps, className: clsx('ams-accordion', className), onKeyDown: keyDown, ref: innerRef, children: children }) }); }); AccordionRoot.displayName = 'Accordion'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-containers-accordion--docs Accordion docs at Amsterdam Design System} */ const Accordion = Object.assign(AccordionRoot, { Section: AccordionSection }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-layout-action-group--docs Action Group docs at Amsterdam Design System} */ const ActionGroup = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("div", { ...restProps, className: clsx('ams-action-group', className), ref: ref, role: "group", children: children })); ActionGroup.displayName = 'ActionGroup'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-buttons-icon-button--docs Icon Button docs at Amsterdam Design System} */ const IconButton = /*#__PURE__*/forwardRef(({ className, color, label, size, svg = CloseIcon, type, ...restProps }, ref) => jsxs("button", { ...restProps, className: clsx('ams-icon-button', color && `ams-icon-button--${color}`, className), ref: ref, type: type || 'button', children: [jsx("span", { className: "ams-visually-hidden", children: label }), jsx(Icon, { size: size, square: true, svg: svg })] })); IconButton.displayName = 'IconButton'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-layout-row--docs Row docs at Amsterdam Design System} */ const Row = /*#__PURE__*/forwardRef(({ align, alignVertical, as: Tag = 'div', children, className, gap, wrap, ...restProps }, ref) => jsx(Tag, { ...restProps, className: clsx('ams-row', align && `ams-row--align-${align}`, alignVertical && `ams-row--align-vertical-${alignVertical}`, gap && `ams-row--gap-${gap}`, wrap && 'ams-row--wrap', className), ref: ref, children: children })); Row.displayName = 'Row'; const iconSvgBySeverity = { error: ErrorFillIcon, success: SuccessFillIcon, warning: WarningFillIcon }; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-feedback-alert--docs Alert docs at Amsterdam Design System} */ const Alert = /*#__PURE__*/forwardRef(({ children, className, closeable, closeButtonLabel = 'Sluiten', heading, headingId = 'ams-alert-heading', headingLevel, onClose, severity, ...restProps }, ref) => { const SeverityIcon = severity ? iconSvgBySeverity[severity] : InfoFillIcon; return jsxs("section", { ...restProps, "aria-labelledby": headingId || undefined, className: clsx('ams-alert', severity && `ams-alert--${severity}`, className), ref: ref, children: [jsx("div", { className: "ams-alert__severity-indicator", children: jsx(Icon, { color: "inverse", size: "heading-3", svg: SeverityIcon }) }), jsxs("div", { className: "ams-alert__content", children: [jsxs(Row, { align: "between", alignVertical: "start", children: [jsx(Heading, { id: headingId || undefined, level: headingLevel, size: "level-3", children: heading }), closeable && jsx(IconButton, { label: closeButtonLabel, onClick: onClose, size: "heading-3" })] }), children] })] }); }); Alert.displayName = 'Alert'; const AvatarContent = ({ imageSrc, initials }) => { if (imageSrc) { return jsx("img", { alt: "", src: imageSrc }); } if (initials.length) { return jsx("span", { "aria-hidden": true, children: initials }); } return jsx(Icon, { size: "small", svg: PersonFillIcon }); }; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-feedback-avatar--docs Avatar docs at Amsterdam Design System} */ const Avatar = /*#__PURE__*/forwardRef(({ className, color, imageSrc, label, ...restProps }, ref) => { const initials = label.slice(0, 2).toUpperCase(); const a11yLabel = initials.length === 0 ? 'Gebruiker' : `Initialen gebruiker: ${initials}`; return jsxs("span", { ...restProps, className: clsx('ams-avatar', color && `ams-avatar--${color}`, imageSrc && 'ams-avatar--has-image', className), ref: ref, children: [jsx("span", { className: "ams-visually-hidden", children: a11yLabel }), jsx(AvatarContent, { imageSrc: imageSrc, initials: initials })] }); }); Avatar.displayName = 'Avatar'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-feedback-badge--docs Badge docs at Amsterdam Design System} */ const Badge = /*#__PURE__*/forwardRef(({ className, color, icon, label, ...restProps }, ref) => jsxs("span", { ...restProps, className: clsx('ams-badge', color && `ams-badge--${color}`, className), ref: ref, children: [icon && jsx(Icon, { svg: icon }), label] })); Badge.displayName = 'Badge'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-text-blockquote--docs Blockquote docs at Amsterdam Design System} */ const Blockquote = /*#__PURE__*/forwardRef(({ children, className, color, ...restProps }, ref) => jsx("blockquote", { ...restProps, className: clsx('ams-blockquote', color && `ams-blockquote--${color}`, className), ref: ref, children: children })); Blockquote.displayName = 'Blockquote'; const BreadcrumbLink = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("li", { className: "ams-breadcrumb__item", children: jsx("a", { ...restProps, className: clsx('ams-breadcrumb__link', className), ref: ref, children: children }) })); BreadcrumbLink.displayName = 'Breadcrumb.Link'; const BreadcrumbRoot = /*#__PURE__*/forwardRef(({ accessibleName, accessibleNameId, children, className, ...restProps }, ref) => { const generatedId = useId(); const labelId = accessibleNameId || generatedId; return jsxs("nav", { ...restProps, "aria-labelledby": labelId, className: clsx('ams-breadcrumb', className), ref: ref, children: [jsx("h2", { "aria-hidden": true, className: "ams-visually-hidden", id: labelId, children: accessibleName || 'Kruimelpad' }), jsx("ol", { className: "ams-breadcrumb__list", children: children })] }); }); BreadcrumbRoot.displayName = 'Breadcrumb'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-navigation-breadcrumb--docs Breadcrumb docs at Amsterdam Design System} */ const Breadcrumb = Object.assign(BreadcrumbRoot, { Link: BreadcrumbLink }); /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const paddingClasses = (componentName, paddingBottom, paddingTop, paddingVertical) => { const classes = []; if (paddingVertical) { return [`ams-${componentName}--padding-vertical--${paddingVertical}`]; } if (paddingBottom) { classes.push(`ams-${componentName}--padding-bottom--${paddingBottom}`); } if (paddingTop) { classes.push(`ams-${componentName}--padding-top--${paddingTop}`); } return classes; }; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const addGridClass = (prefix, value) => { if (value === 'all' || typeof value === 'number') { return [`${prefix}${value}`]; } else if (value) { const { narrow, medium, wide } = value; return [`${prefix}${narrow}`, `${prefix}${medium}-medium`, `${prefix}${wide}-wide`]; } return []; }; const gridCellClasses = (colSpan, colStart, rowSpan) => [...addGridClass('ams-grid__cell--span-', colSpan), ...addGridClass('ams-grid__cell--start-', colStart), ...addGridClass('ams-grid__cell--row-span-', rowSpan)]; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const breakoutCellClasses = (colSpan, colStart, rowSpan, rowStart) => [...addGridClass('ams-breakout__cell--col-span-', colSpan), ...addGridClass('ams-breakout__cell--col-start-', colStart), ...addGridClass('ams-breakout__cell--row-span-', rowSpan), ...addGridClass('ams-breakout__cell--row-start-', rowStart)]; const BreakoutCell = /*#__PURE__*/forwardRef(({ as: Tag = 'div', children, className, colSpan, colStart, has, rowSpan, rowStart, ...restProps }, ref) => jsx(Tag, { ...restProps, className: clsx('ams-breakout__cell', breakoutCellClasses(colSpan, colStart, rowSpan, rowStart), has && `ams-breakout__cell--has-${has}`, className), ref: ref, children: children })); BreakoutCell.displayName = 'Breakout.Cell'; const BreakoutRoot = /*#__PURE__*/forwardRef(({ children, className, gapVertical, paddingBottom, paddingTop, paddingVertical, ...restProps }, ref) => jsx("div", { ...restProps, className: clsx('ams-breakout', gapVertical && `ams-breakout--gap-vertical--${gapVertical}`, paddingClasses('breakout', paddingBottom, paddingTop, paddingVertical), className), ref: ref, children: children })); BreakoutRoot.displayName = 'Breakout'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-layout-breakout--docs Breakout docs at Amsterdam Design System} */ const Breakout = Object.assign(BreakoutRoot, { Cell: BreakoutCell }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-buttons-button--docs Button docs at Amsterdam Design System} */ const Button = /*#__PURE__*/forwardRef(({ children, className, disabled, icon, iconBefore, iconOnly, type, variant = 'primary', ...restProps }, ref) => jsxs("button", { ...restProps, className: clsx('ams-button', `ams-button--${variant}`, icon && iconOnly && `ams-button--icon-only`, className), disabled: disabled, ref: ref, type: type || 'button', children: [icon && (iconBefore || iconOnly) && jsx(Icon, { square: iconOnly, svg: icon }), icon && iconOnly ? jsx("span", { className: "ams-visually-hidden", children: children }) : children, icon && !iconBefore && !iconOnly && jsx(Icon, { svg: icon })] })); Button.displayName = 'Button'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-navigation-call-to-action-link--docs CallToActionLink docs at Amsterdam Design System} */ const CallToActionLink = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("a", { ...restProps, className: clsx('ams-call-to-action-link', className), ref: ref, children: children })); CallToActionLink.displayName = 'CallToActionLink'; const CardHeading = /*#__PURE__*/forwardRef(({ children, className, size = 'level-3', ...restProps }, ref) => jsx(Heading, { ...restProps, className: clsx('ams-card__heading', className), ref: ref, size: size, children: children })); CardHeading.displayName = 'Card.Heading'; const wrapChildren = (size, children) => { if (size === 'large') return jsx("b", { className: "ams-paragraph__b", children: children }); if (size === 'small') return jsx("small", { className: "ams-paragraph__small", children: children }); return children; }; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-text-paragraph--docs Paragraph docs at Amsterdam Design System} */ const Paragraph = /*#__PURE__*/forwardRef(({ children, className, color, size, ...restProps }, ref) => jsx("p", { className: clsx('ams-paragraph', color && `ams-paragraph--${color}`, size && `ams-paragraph--${size}`, className), ref: ref, ...restProps, children: wrapChildren(size, children) })); Paragraph.displayName = 'Paragraph'; const CardHeadingGroup = /*#__PURE__*/forwardRef(({ children, className, tagline, ...restProps }, ref) => jsxs("hgroup", { ...restProps, className: clsx('ams-card__heading-group', className), ref: ref, children: [children, jsx(Paragraph, { size: "small", children: tagline })] })); CardHeadingGroup.displayName = 'Card.HeadingGroup'; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const generateAspectRatioClass = aspectRatio => aspectRatio && `ams-aspect-ratio-${aspectRatio.replace(':', '-')}`; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-media-image--docs Image docs at Amsterdam Design System} */ const Image = /*#__PURE__*/forwardRef(({ aspectRatio, className, width, ...restProps }, ref) => jsx("img", { ...restProps, className: clsx('ams-image', generateAspectRatioClass(aspectRatio), className), ref: ref, width: width ?? 600 })); Image.displayName = 'Image'; const CardImage = /*#__PURE__*/forwardRef(({ className, ...restProps }, ref) => jsx(Image, { ...restProps, className: clsx('ams-card__image', className), ref: ref })); CardImage.displayName = 'Card.Image'; const CardLink = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("a", { ...restProps, className: clsx('ams-card__link', className), ref: ref, children: children })); CardLink.displayName = 'Card.Link'; const CardRoot = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("article", { ...restProps, className: clsx('ams-card', className), ref: ref, children: children })); CardRoot.displayName = 'Card'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-navigation-card--docs Card docs at Amsterdam Design System} */ const Card = Object.assign(CardRoot, { Heading: CardHeading, HeadingGroup: CardHeadingGroup, Image: CardImage, Link: CardLink }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-character-count--docs Character Count docs at Amsterdam Design System} */ const CharacterCount = /*#__PURE__*/forwardRef(({ className, length, maxLength, ...restProps }, ref) => jsx("div", { ...restProps, className: clsx('ams-character-count', length > maxLength && 'ams-character-count--error', className), ref: ref, role: "status", children: `${length} van ${maxLength} tekens` })); CharacterCount.displayName = 'CharacterCount'; const SvgCheckbox = props => jsxs("svg", { "aria-hidden": "true", focusable: "false", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", ...props, children: [jsx("rect", { className: "ams-checkbox__rectangle", fill: "none", height: "22", stroke: "black", strokeWidth: "2", width: "22", x: "1", y: "1" }), jsx("rect", { className: "ams-checkbox__hover-indicator", fill: "none", height: "20", stroke: "black", strokeWidth: "1", width: "20", x: "2", y: "2" }), jsx("path", { className: "ams-checkbox__checked-indicator", d: "M3.251 13.017L8.554 18.761L20.749 5.239", fill: "none", stroke: "black", strokeWidth: "3" }), jsx("line", { className: "ams-checkbox__indeterminate-indicator", fill: "none", stroke: "black", strokeWidth: "3", x1: "4", x2: "20", y1: "12", y2: "12" })] }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-checkbox--docs Checkbox docs at Amsterdam Design System} */ const Checkbox = /*#__PURE__*/forwardRef(({ children, className, icon = SvgCheckbox, id, indeterminate, invalid, ...restProps }, ref) => { const inputId = id || useId(); const innerRef = useRef(null); // use a passed ref if it's there, otherwise use innerRef useImperativeHandle(ref, () => innerRef.current); // set input to indeterminate useEffect(() => { if (innerRef.current) { innerRef.current.indeterminate = Boolean(indeterminate); } }, [innerRef, indeterminate]); return ( // This div is here because NVDA doesn't match the input to the label // without a containing element jsxs("div", { className: clsx('ams-checkbox', className), children: [jsx("input", { ...restProps, "aria-invalid": invalid || undefined, className: "ams-checkbox__input", id: inputId, ref: innerRef, type: "checkbox" }), jsxs("label", { className: "ams-checkbox__label", htmlFor: inputId, children: [jsx("span", { className: "ams-checkbox__icon-container", hidden: true, children: typeof icon === 'function' ? icon({}) : icon }), children] })] }) ); }); Checkbox.displayName = 'Checkbox'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-layout-column--docs Column docs at Amsterdam Design System} */ const Column = /*#__PURE__*/forwardRef(({ align, alignHorizontal, as: Tag = 'div', children, className, gap, ...restProps }, ref) => jsx(Tag, { ...restProps, className: clsx('ams-column', align && `ams-column--align-${align}`, alignHorizontal && `ams-column--align-horizontal-${alignHorizontal}`, gap && `ams-column--gap-${gap}`, className), ref: ref, children: children })); Column.displayName = 'Column'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-date-input--docs Date Input docs at Amsterdam Design System} */ const DateInput = /*#__PURE__*/forwardRef(({ className, invalid, type = 'date', ...restProps }, ref) => jsx("input", { ...restProps, "aria-invalid": invalid || undefined, className: clsx('ams-date-input', className), ref: ref, type: type })); DateInput.displayName = 'DateInput'; const DescriptionListDescription = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("dd", { ...restProps, className: clsx('ams-description-list__description', className), ref: ref, children: children })); DescriptionListDescription.displayName = 'DescriptionList.Description'; const DescriptionListSection = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("div", { ...restProps, className: clsx('ams-description-list__section', className), ref: ref, children: children })); DescriptionListSection.displayName = 'DescriptionList.Section'; const DescriptionListTerm = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("dt", { ...restProps, className: clsx('ams-description-list__term', className), ref: ref, children: children })); DescriptionListTerm.displayName = 'DescriptionList.Term'; const DescriptionListRoot = /*#__PURE__*/forwardRef(({ children, className, color, termsWidth, ...restProps }, ref) => jsx("dl", { ...restProps, className: clsx('ams-description-list', color && `ams-description-list--${color}`, termsWidth && `ams-description-list--${termsWidth}`, className), ref: ref, children: children })); DescriptionListRoot.displayName = 'DescriptionList'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-text-description-list--docs Description List docs at Amsterdam Design System} */ const DescriptionList = Object.assign(DescriptionListRoot, { Description: DescriptionListDescription, Section: DescriptionListSection, Term: DescriptionListTerm }); const closeDialog = event => event.currentTarget.closest('dialog')?.close(); const openDialog = id => document.querySelector(id)?.showModal(); const DialogRoot = /*#__PURE__*/forwardRef(({ children, className, closeButtonLabel = 'Sluiten', footer, heading, ...restProps }, ref) => jsxs("dialog", { ...restProps, className: clsx('ams-dialog', className), ref: ref, children: [jsxs("header", { className: "ams-dialog__header", children: [jsx(Heading, { level: 1, size: "level-3", children: heading }), jsx(IconButton, { label: closeButtonLabel, onClick: closeDialog, size: "heading-3", type: "button" })] }), jsx("div", { className: "ams-dialog__body", children: children }), footer && jsx("footer", { className: "ams-dialog__footer", children: footer })] })); DialogRoot.displayName = 'Dialog'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-containers-dialog--docs Dialog docs at Amsterdam Design System} */ const Dialog = Object.assign(DialogRoot, { close: closeDialog, open: openDialog }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-error-message--docs Error Message docs at Amsterdam Design System} */ const ErrorMessage = /*#__PURE__*/forwardRef(({ children, className, icon = WarningIcon, prefix = 'Invoerfout', ...restProps }, ref) => jsxs("p", { ...restProps, className: clsx('ams-error-message', className), ref: ref, children: [jsx(Icon, { svg: icon }), prefix && jsx("span", { className: "ams-visually-hidden", children: `${prefix}: ` }), children] })); ErrorMessage.displayName = 'ErrorMessage'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-field--docs Field docs at Amsterdam Design System} */ const Field = /*#__PURE__*/forwardRef(({ children, className, invalid, ...restProps }, ref) => jsx("div", { ...restProps, className: clsx('ams-field', invalid && 'ams-field--invalid', className), ref: ref, children: children })); Field.displayName = 'Field'; const getHintText = ({ hint, optional }) => { if (hint) { return hint; } else if (optional) { return 'niet verplicht'; } return null; }; const Hint = /*#__PURE__*/forwardRef(({ className, hint, inFieldSet, optional, ...restProps }, ref) => { const hintText = getHintText({ hint, optional }); return hintText && jsxs("span", { ...restProps, className: clsx('ams-hint', inFieldSet && 'ams-hint--in-fieldset', className), ref: ref, children: ["(", hintText, ")"] }); }); Hint.displayName = 'Hint'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-field-set--docs Field Set docs at Amsterdam Design System} */ const FieldSet = /*#__PURE__*/forwardRef(({ children, className, hint, inFieldSet, invalid, legend, legendIsPageHeading, optional, ...restProps }, ref) => { const legendContent = jsxs(Fragment, { children: [legend, " ", jsx(Hint, { hint: hint, inFieldSet: inFieldSet, optional: optional })] }); return jsxs("fieldset", { ...restProps, className: clsx('ams-field-set', invalid && 'ams-field-set--invalid', className), ref: ref, children: [jsx("legend", { className: clsx('ams-field-set__legend', inFieldSet && 'ams-field-set__legend--in-fieldset'), children: legendIsPageHeading ? jsx("h1", { className: "ams-field-set__heading", children: legendContent }) : legendContent }), children] }); }); FieldSet.displayName = 'FieldSet'; const FigureCaption = /*#__PURE__*/forwardRef(({ children, className, color, ...restProps }, ref) => jsx("figcaption", { ...restProps, className: clsx('ams-figure__caption', color && `ams-figure__caption--${color}`, className), ref: ref, children: children })); FigureCaption.displayName = 'Figure.Caption'; const FigureRoot = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("figure", { ...restProps, className: clsx('ams-figure', className), ref: ref, children: children })); FigureRoot.displayName = 'Figure'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-media-figure--docs Figure docs at Amsterdam Design System} */ const Figure = Object.assign(FigureRoot, { Caption: FigureCaption }); /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-file-input--docs File Input docs at Amsterdam Design System} */ const FileInput = /*#__PURE__*/forwardRef(({ className, ...restProps }, ref) => jsx("input", { ...restProps, className: clsx('ams-file-input', className), ref: ref, type: "file" })); FileInput.displayName = 'FileInput'; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ /** * @param fileSize The size of the file in bytes. * @param precision The number of significant digits in the output. * @returns A human readable file size */ const formatFileSize = (fileSize, precision = 3) => { const UNITS = ['bytes', 'kB', 'MB', 'GB']; if (fileSize === 0) return '0 bytes'; const exponent = Math.floor(Math.log10(fileSize) / 3); const size = (fileSize / Math.pow(1000, exponent)).toPrecision(precision); return `${size} ${UNITS[exponent]}`; }; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ /** * * @param fileType * @returns Human readable file type */ const formatFileType = fileType => { switch (fileType) { case 'application/msword': case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': return 'Word'; case 'application/pdf': return 'pdf'; case 'application/vnd.ms-excel': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': return 'Excel'; case 'application/vnd.ms-powerpoint': case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': return 'PowerPoint'; case 'image/gif': return 'gif'; case 'image/jpeg': return 'jpg'; case 'image/png': return 'png'; case 'text/plain': return 'txt'; default: return 'Document'; } }; const FileListItem = /*#__PURE__*/forwardRef(({ className, file, onDelete, ...restProps }, ref) => jsxs("li", { ...restProps, className: clsx('ams-file-list__item', className), ref: ref, children: [jsx("div", { className: "ams-file-list__item-preview", children: file.type.startsWith('image/') ? jsx("img", { alt: file.name, src: URL.createObjectURL(file) }) : jsx(Icon, { size: "heading-3", square: true, svg: DocumentIcon }) }), jsxs("div", { className: "ams-file-list__item-info", children: [file.name, jsxs("div", { className: "ams-file-input__item-details", children: ["(", formatFileType(file.type), ", ", formatFileSize(file.size), ")"] })] }), onDelete && jsx("div", { children: jsx(Button, { onClick: () => onDelete(), variant: "tertiary", children: "Verwijder" }) })] })); FileListItem.displayName = 'FileList.Item'; const FileListRoot = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => jsx("ul", { ...restProps, className: clsx('ams-file-list', className), ref: ref, children: children })); FileListRoot.displayName = 'FileList'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-file-list--docs File List docs at Amsterdam Design System} */ const FileList = Object.assign(FileListRoot, { Item: FileListItem }); const GridCell = /*#__PURE__*/forwardRef(({ appearance, as: Tag = 'div', children, className, rowSpan, span, start, ...restProps }, ref) => jsx(Tag, { ...restProps, className: clsx('ams-grid__cell', appearance && `ams-grid__cell--${appearance}`, gridCellClasses(span, start, rowSpan), className), ref: ref, children: children })); GridCell.displayName = 'Grid.Cell'; const GridRoot = /*#__PURE__*/forwardRef(({ as: Tag = 'div', children, className, gapVertical, paddingBottom, paddingTop, paddingVertical, ...restProps }, ref) => jsx(Tag, { ...restProps, className: clsx('ams-grid', gapVertical && `ams-grid--gap-vertical--${gapVertical}`, paddingClasses('grid', paddingBottom, paddingTop, paddingVertical), className), ref: ref, children: children })); GridRoot.displayName = 'Grid'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-layout-grid--docs Grid docs at Amsterdam Design System} */ const Grid = Object.assign(GridRoot, { Cell: GridCell }); const ImageSliderSlide = ({ alt, aspectRatio, caption, className, currentSlideId, index, sizes, src, srcSet, ...restProps }) => { const isCurrentSlide = index === currentSlideId; const slideProps = { 'aria-hidden': isCurrentSlide ? undefined : true, className: clsx('ams-image-slider__slide', className) }; const imageProps = { alt, aspectRatio, sizes, src, srcSet }; return caption ? jsxs(Figure, { ...restProps, ...slideProps, className: clsx(slideProps.className, 'ams-image-slider__figure'), children: [jsx(Image, { ...imageProps }), jsx(Figure.Caption, { className: "ams-image-slider__caption", children: caption })] }) : jsx(Image, { ...restProps, ...imageProps, ...slideProps }); }; ImageSliderSlide.displayName = 'ImageSliderSlide'; const ImageSliderThumbnails = ({ currentSlideId, imageLabel, scrollToSlide, thumbnails, ...restProps }) => { const handleKeyDown = event => { const element = event.currentTarget.children[currentSlideId]; if (event.key === 'ArrowRight') { const nextElement = element?.nextElementSibling; if (nextElement) { nextElement.focus(); scrollToSlide(currentSlideId + 1); } } if (event.key === 'ArrowLeft') { const previousElement = element?.previousElementSibling; if (previousElement) { previousElement.focus(); scrollToSlide(currentSlideId - 1); } } }; return jsx("nav", { ...restProps, className: "ams-image-slider__thumbnails", onKeyDown: handleKeyDown, role: "tablist", children: thumbnails.map(({ alt, aspectRatio, src }, index) => jsx("button", { "aria-label": `${imageLabel} ${index + 1}: ${alt}`, "aria-posinset": index + 1, "aria-selected": currentSlideId === index ? 'true' : 'false', "aria-setsize": thumbnails.length, className: clsx('ams-image-slider__thumbnail', currentSlideId === index && 'ams-image-slider__thumbnail--in-view', generateAspectRatioClass(aspectRatio)), onClick: () => scrollToSlide(index), role: "tab", style: { backgroundImage: `url(${src})` }, tabIndex: currentSlideId === index ? 0 : -1, type: "button" }, `${index}-${src}`)) }); }; function debounce(fn, delay) { let timer = null; return function (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } const scrollToSlide = (id, ref) => { const element = ref.current?.children[id]; const scrollerElement = ref.current; if (!element || !scrollerElement) return; scrollerElement.scrollTo({ left: element.offsetLeft }); }; const scrollToCurrentSlideOnResize = ({ currentSlideId, ref }) => { const scrollerElement = ref.current; const currentSlideElement = ref.current?.children[currentSlideId]; if (!scrollerElement || !currentSlideElement) return; const expectedScrollLeft = currentSlideElement.offsetLeft; if (Math.abs(scrollerElement.scrollLeft - expectedScrollLeft) < 1) return; scrollToSlide(currentSlideId, ref); }; const setCurrentSlideIdToVisibleSlide = ({ observations, ref, setCurrentSlideId }) => { const images = Array.from(ref.current?.children || []); if (images.length === 0) return; observations.forEach(observation => { if (observation.isIntersecting) { setCurrentSlideId(images.indexOf(observation.target)); } }); }; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-media-image-slider--docs Image Slider docs at Amsterdam Design System} */ const ImageSlider = /*#__PURE__*/forwardRef(({ className, controls, imageLabel = 'Afbeelding', images, nextLabel = 'Volgende', previousLabel = 'Vorige', ...restProps }, ref) => { if (images.length === 0) return null; const [currentSlideId, setCurrentSlideId] = useState(0); const scrollerRef = useRef(null); const isAtStart = currentSlideId === 0; const isAtEnd = currentSlideId === images.length - 1; useEffect(() => { if (!scrollerRef.current) return undefined; const observerOptions = { root: scrollerRef.current, threshold: 0.6 }; const observer = new IntersectionObserver(observations => setCurrentSlideIdToVisibleSlide({ observations, ref: scrollerRef, setCurrentSlideId }), observerOptions); const slides = Array.from(scrollerRef.current.children); slides.forEach(slide => observer.observe(slide)); return () => observer.disconnect(); }, []); useEffect(() => { const handleResize = debounce(() => scrollToCurrentSlideOnResize({ currentSlideId, ref: scrollerRef }), 100); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, [currentSlideId]); return jsxs("div", { ...restProps, "aria-roledescription": "carousel", className: clsx('ams-image-slider', className), ref: ref, children: [controls && jsxs("div", { className: "ams-image-slider__controls", children: [jsx(Button, { className: "ams-image-slider__control", color: "inverse", disabled: isAtStart, icon: ChevronBackwardIcon, iconOnly: true, onClick: () => scrollToSlide(currentSlideId - 1, scrollerRef), children: previousLabel }), jsx(Button, { className: "ams-image-slider__control", color: "inverse", disabled: isAtEnd, icon: ChevronForwardIcon, iconOnly: true, onClick: () => scrollToSlide(currentSlideId + 1, scrollerRef), children: nextLabel })] }), jsx("div", { "aria-live": "polite", className: "ams-image-slider__scroller", ref: scrollerRef, role: "group", tabIndex: 0, children: images.map((image, index) => jsx(ImageSliderSlide, { ...image, currentSlideId: currentSlideId, index: index }, `${index}-${image.src}`)) }), jsx(ImageSliderThumbnails, { currentSlideId: currentSlideId, imageLabel: imageLabel, scrollToSlide: id => scrollToSlide(id, scrollerRef), thumbnails: images })] }); }); ImageSlider.displayName = 'ImageSlider'; /** One link with a Link List. */ const LinkListLink = /*#__PURE__*/forwardRef(({ children, className, color, icon = ChevronForwardIcon, size, ...restProps }, ref) => { return jsx("li", { children: jsxs("a", { className: clsx('ams-link-list__link', color && `ams-link-list__link--${color}`, size && `ams-link-list__link--${size}`, className), ref: ref, ...restProps, children: [jsx(Icon, { size: size, svg: icon }), children] }) }); }); LinkListLink.displayName = 'LinkList.Link'; /** A collection of related links. */ const LinkListRoot = /*#__PURE__*/forwardRef(({ children, className, ...restProps }, ref) => { return jsx("ul", { className: clsx('ams-link-list', className), ref: ref, ...restProps, children: children }); }); LinkListRoot.displayName = 'LinkList'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-navigation-link-list--docs Link List docs at Amsterdam Design System} */ const LinkList = Object.assign(LinkListRoot, { Link: LinkListLink }); const InvalidFormAlertWithErrors = /*#__PURE__*/forwardRef(({ className, errors, focusOnRender = true, hasFocusedOnce, heading = 'Verbeter de fouten voor u verder gaat', headingLevel, setHasFocusedOnce, ...restProps }, ref) => { const innerRef = useRef(null); // use a passed ref if it's there, otherwise use innerRef useImperativeHandle(ref, () => innerRef.current); useEffect(() => { if (innerRef.current && focusOnRender && !hasFocusedOnce) { innerRef.current.focus(); setHasFocusedOnce(true); } }, [innerRef]); return jsx(Alert, { ...restProps, className: clsx('ams-invalid-form-alert', className), heading: heading, // Remove the default label for the Alert. // Otherwise, focusing on the Alert causes NVDA to read the label twice. headingId: null, headingLevel: headingLevel, ref: innerRef, severity: "error", tabIndex: -1, children: jsx(LinkList, { children: errors.map(({ id, label }) => jsx(LinkList.Link, { href: id, children: label }, `${id}-${label}`)) }) }); }); InvalidFormAlertWithErrors.displayName = 'InvalidFormAlertWithErrors'; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ const useAddErrorCountToDocumentTitle = (/** The list of error messages used to calculate the error count. */ errors, /** The text following the error count. */ label = { plural: 'invoerfouten', singular: 'invoerfout' }) => { const [documentTitle, setDocumentTitle] = useState(); useEffect(() => { setDocumentTitle(document.title); }, []); if (!documentTitle) return null; if (errors.length === 1) { document.title = `(${errors.length} ${label.singular}) ${documentTitle}`; } else if (errors.length > 1) { document.title = `(${errors.length} ${label.plural}) ${documentTitle}`; } else { document.title = documentTitle; } return null; }; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-invalid-form-alert--docs Invalid Form Alert docs at Amsterdam Design System} */ const InvalidFormAlert = /*#__PURE__*/forwardRef(({ errorCountLabel, errors, ...restProps }, ref) => { // An Invalid Form Alert without errors only resets the document title. // With errors, it renders the InvalidFormAlertWithErrors component. useAddErrorCountToDocumentTitle(errors, errorCountLabel); // Focus should only be set on first render of InvalidFormAlertWithErrors. // Subsequent renders should not set focus. const [hasFocusedOnce, setHasFocusedOnce] = useState(false); if (errors.length === 0) return undefined; return jsx(InvalidFormAlertWithErrors, { ...restProps, errors: errors, hasFocusedOnce: hasFocusedOnce, ref: ref, setHasFocusedOnce: setHasFocusedOnce }); }); InvalidFormAlert.displayName = 'InvalidFormAlert'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-forms-label--docs Label docs at Amsterdam Design System} */ const Label = /*#__PURE__*/forwardRef(({ children, className, hint, inFieldSet, isPageHeading, optional, ...restProps }, ref) => { const labelElement = jsxs("label", { ...restProps, className: clsx('ams-label', inFieldSet && 'ams-label--in-fieldset', className), ref: ref, children: [children, " ", jsx(Hint, { hint: hint, inFieldSet: inFieldSet, optional: optional })] }); return isPageHeading ? jsx("h1", { className: "ams-label__heading", children: labelElement }) : labelElement; }); Label.displayName = 'Label'; /** * @see {@link https://designsystem.amsterdam/?path=/docs/components-navigation-link--docs Link docs at Amsterdam Design System} */ const Link = /*#__PURE__*/forwardRef(({ children, className, color, ...restProps }, ref) => jsx("a", { ...restProps, className: clsx('ams-link', color && `ams-link--${color}`, className), ref: ref, children: children })); Link.displayName = 'Link'; const AmsterdamEnglishLogo = /*#__PURE__*/forwardRef((props, ref) => jsxs("svg", { className: "ams-logo", focusable: "false", height: "2.5rem", ref: ref, role: "img", viewBox: "0 0 115 40", xmlns: "http://www.w3.org/2000/svg", ...props, children: [jsx("path", { className: "ams-logo__emblem", d: "m0 37.683 3.532-3.532L0 30.62l2.355-2.355 3.532 3.532 3.532-3.532 2.355 2.355-3.532 3.532 3.532 3.532L9.419 40l-3.532-3.532L2.355 40zM0 9.406l3.532-3.532L0 2.342 2.355-.013l3.532 3.532L9.419-.013l2.355 2.354-3.532 3.532 3.532 3.532-2.355 2.355-3.532-3.532-3.532 3.532zm0 14.151 3.532-3.532L0 16.493l2.355-2.355 3.532 3.532 3.532-3.532 2.355 2.355-3.532 3.532 3.532 3.532-2.355 2.355-3.532-3.532-3.532 3.531z", fill: "#EC0000" }), jsx("path", { className: "ams-logo__text-primary", d: "M16.456 8.579c0-3.795 2.613-6.408 6.389-6.408 1.812 0 3.376.648 4.558 1.869l-1.659 1.602c-.706-.801-1.717-1.24-2.88-1.24-2.251 0-3.815 1.717-3.815 4.196 0 2.46 1.583 4.196 3.834 4.196 1.183 0 2.27-.458 2.956-1.24l1.64 1.583c-1.125 1.221-2.746 1.888-4.616 1.888-3.776 0-6.408-2.632-6.408-6.447m14-4.404c-.82 0-1.411-.572-1.411-1.373s.591-1.373 1.411-1.373 1.411.572 1.411 1.373-.591 1.373-1.411 1.373m-1.183 1.202h2.365v9.421h-2.365zm5.531 6.045V7.34h-1.621V5.375h.858c.782 0 1.087-.305 1.087-1.087V2.819h2.022v2.556h2.289V7.34h-2.289v4.082c0 .915.477 1.43 1.354 1.43.267 0 .591-.038.782-.095v1.984c-.286.076-.82.133-1.24.133-2.136 0-3.242-1.182-3.242-3.452m6.18 5.626 1.488-1.488c.534.629 1.335.954 2.346.954 1.392 0 2.213-.801 2.213-2.155v-1.411h-.038c-.42.935-1.278 1.507-2.327 1.507-2.308 0-3.49-1.335-3.49-3.948V5.375h2.365v4.692c0 1.583.553 2.327 1.698 2.327 1.163 0 1.812-.858 1.812-2.384V5.375h2.365v9.079c0 2.518-1.774 4.101-4.558 4.101-1.717 0-3.033-.515-3.872-1.507m15.141-6.962c0-2.88 2.098-4.94 5.016-4.94s5.016 2.06 5.016 4.94-2.098 4.94-5.016 4.94-5.016-2.06-5.016-4.94m5.016 2.88c1.526 0 2.594-1.182 2.594-2.88s-1.068-2.88-2.594-2.88-2.594 1.183-2.594 2.88 1.068 2.88 2.594 2.88m7.534-5.626h-1.602V5.375h1.602V4.154c0-2.155 1.278-3.414 3.471-3.414.267 0 .668.038.877.076v2.041a3.7 3.7 0 0 0-.82-.095c-.744 0-1.163.496-1.163 1.392v1.221h2.289V7.34h-2.289v7.457h-2.365zM20.9 25.287h2.861l4.959 12.397h-2.651l-1.03-2.727h-5.512l-1.03 2.727h-2.556zm-.629 7.61h4.005l-1.984-5.226h-.038zm10.013-4.635h2.212v1.278h.038c.477-.973 1.316-1.507 2.403-1.507 1.221 0 2.136.534 2.708 1.602.572-1.03 1.621-1.602 2.956-1.602 2.327 0 3.452 1.297 3.452 3.948v5.703h-2.365v-5.302c0-1.545-.534-2.289-1.64-2.289s-1.697.82-1.697 2.365v5.226h-2.365v-5.302c0-1.564-.515-2.289-1.64-2.289-1.087 0-1.697.839-1.697 2.365v5.226h-2.365zm18.118 5.474c-1.278-.381-2.518-1.068-2.518-2.785 0-1.736 1.45-2.918 3.605-2.918 1.449 0 2.575.515 3.204 1.469l-1.354 1.354c-.477-.591-1.125-.916-1.831-.916-.801 0-1.297.362-1.297.935 0 .763.801.896 1.965 1.259 1.278.381 2.518 1.068 2.518 2.785 0 1.774-1.526 2.994-3.776 2.994-1.469 0-2.651-.515-3.338-1.488l1.354-1.354c.515.61 1.202.935 1.965.935.916 0 1.469-.382 1.469-1.011 0-.763-.801-.896-1.965-1.259m6.789.572v-4.082h-1.621v-1.965h.858c.782 0 1.087-.305 1.087-1.087v-1.469h2.022v2.556h2.289v1.965h-2.289v4.082c0 .916.477 1.43 1.354 1.43.267 0 .591-.038.782-.095v1.984c-.286.076-.82.134-1.24.134-2.136 0-3.242-1.183-3.242-3.452m5.798-1.336c0-2.918 1.964-4.94 4.768-4.94s4.749 2.003 4.749 4.883c0 .229-.038.591-.076.839h-7.057c.172 1.278 1.259 2.136 2.651 2.136 1.03 0 1.926-.381 2.518-1.068l1.43 1.392c-.858 1.106-2.346 1.698-4.063 1.698-2.899 0-4.921-2.041-4.921-4.94m2.384-.954h4.749c-.153-1.24-1.106-2.079-2.384-2.079s-2.231.839-2.365 2.079m9.099-3.757h2.231v1.564h.038c.458-1.068 1.297-1.64 2.403-1.64.286 0 .687.038.839.095v2.251c-.267-.076-.782-.133-1.163-.133-1.202 0-1.984.916-1.984 2.327v4.959h-2.365zm6.179 4.749c0-2.918 1.926-4.978 4.654-4.978 1.259 0 2.289.553 2.937 1.564h.038v-5.741h2.365v13.828h-2.232v-1.469h-.038c-.61 1.068-1.755 1.698-3.071 1.698-2.727 0-4.654-2.041-4.654-4.902m7.629-.038c0-1.697-1.049-2.823-2.594-2.823-1.564 0-2.613 1.144-2.613 2.823s1.049 2.823 2.613 2.823c1.545 0 2.594-1.125 2.594-2.823m4.178 2.022c0-1.812 1.507-2.899 4.024-2.918l1.831-.019v-.305c0-1.106-.706-1.678-1.984-1.678-.839 0-1.583.324-2.098.915l-1.43-1.392c.82-1.011 2.136-1.564 3.757-1.564 2.518 0 4.12 1.373 4.12 3.56