@stratakit/structures
Version:
Medium-sized component structures for the Strata design system
145 lines (144 loc) • 5.01 kB
JavaScript
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
};