UNPKG

@stratakit/structures

Version:

Medium-sized component structures for the Strata design system

145 lines (144 loc) 5.01 kB
import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import * as React from "react"; import { Collection, CollectionItem, useCollectionStore } from "@ariakit/react/collection"; import { Dialog, DialogDisclosure, DialogProvider } from "@ariakit/react/dialog"; import { Role } from "@ariakit/react/role"; import { useStoreState } from "@ariakit/react/store"; import { Button, Text, VisuallyHidden } from "@stratakit/bricks"; import { IconButtonPresentation } from "@stratakit/bricks/secret-internals"; import { forwardRef, useControlledState } from "@stratakit/foundations/secret-internals"; import cx from "classnames"; import { ChevronDown, StatusIcon } from "./~utils.icons.js"; import { useInit } from "./~utils.useInit.js"; const ErrorRegionRoot = forwardRef((props, forwardedRef) => { useInit(); const { label, items = [], open: openProp, setOpen: setOpenProp, ...rest } = props; const labelId = React.useId(); const sectionLabelledBy = props["aria-label"] ? void 0 : label ? labelId : void 0; const visible = items.length > 0; const [open, setOpen] = useControlledState(false, openProp, setOpenProp); const containerRef = React.useRef(null); const pulse = () => { const el = containerRef.current; if (!el) return; const id = "--\u{1F95D}ErrorRegion-pulse"; const animations = el.getAnimations({ subtree: true }); if (animations.find((animation) => animation.id === id)) return; el.animate([{ boxShadow: "0 0 0 0 var(--stratakit-color-border-attention-base)", opacity: 1 }, { boxShadow: "0 0 15px 2px var(--stratakit-color-border-attention-base)", opacity: 0.7, offset: 0.5 }, { boxShadow: "0 0 0 0 var(--stratakit-color-border-attention-base)", opacity: 1 }], { id, duration: 600, easing: "cubic-bezier(0.4, 0, 0.2, 1)", pseudoElement: "::before" }); }; const store = useCollectionStore({ setItems: (newItems) => { const prevItemsSet = new Set(prevItems.map((item) => item.id)); const addedItems = newItems.filter((item_0) => !prevItemsSet.has(item_0.id)); if (addedItems.length === 0) return; pulse(); setLiveLabel(label); } }); const prevItems = useStoreState(store, "items"); const [liveLabel, setLiveLabel] = React.useState(label); return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "polite", "aria-atomic": true, children: liveLabel === label ? liveLabel : void 0 }), /* @__PURE__ */ jsx(DialogProvider, { open, setOpen, children: /* @__PURE__ */ jsx(Role.section, { "aria-labelledby": sectionLabelledBy, ...rest, className: cx("\u{1F95D}ErrorRegion", props.className), "data-_sk-visible": visible, "data-_sk-expanded": open, ref: forwardedRef, children: /* @__PURE__ */ jsxs("div", { className: "\u{1F95D}ErrorRegionContainer", ref: containerRef, children: [/* @__PURE__ */ jsxs(DialogDisclosure, { className: "\u{1F95D}ErrorRegionHeader", render: /* @__PURE__ */ jsx(Button, { variant: "ghost" }), children: [/* @__PURE__ */ jsx(StatusIcon, { tone: "attention", className: "\u{1F95D}ErrorRegionIcon" }), /* @__PURE__ */ jsx(Text, { render: /* @__PURE__ */ jsx("span", {}), id: labelId, className: "\u{1F95D}ErrorRegionLabel", variant: "body-sm", children: label }), /* @__PURE__ */ jsx(IconButtonPresentation, { "aria-hidden": "true", variant: "ghost", children: /* @__PURE__ */ jsx(ChevronDown, {}) })] }), /* @__PURE__ */ jsx(Dialog, { className: "\u{1F95D}ErrorRegionDialog", portal: false, modal: false, autoFocusOnShow: false, "aria-labelledby": labelId, children: /* @__PURE__ */ jsx(Collection, { store, className: "\u{1F95D}ErrorRegionItems", role: "list", children: items }) })] }) }) })] }); }); const ErrorRegionItem = forwardRef((props, forwardedRef) => { const generatedId = React.useId(); const { message, messageId = `${generatedId}-message`, actions, ...rest } = props; return /* @__PURE__ */ jsxs(CollectionItem, { ...rest, role: "listitem", className: cx("\u{1F95D}ErrorRegionItem", props.className), ref: forwardedRef, children: [/* @__PURE__ */ jsx(Text, { id: messageId, variant: "body-sm", children: message }), /* @__PURE__ */ jsx("div", { className: "\u{1F95D}ErrorRegionItemActions", children: actions })] }); }); export { ErrorRegionItem as Item, ErrorRegionRoot as Root };