@stratakit/structures
Version:
Medium-sized component structures for the Strata design system
171 lines (170 loc) • 5.64 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";
const ErrorRegionRoot = forwardRef(
(props, forwardedRef) => {
const {
label,
items,
open: openProp,
setOpen: setOpenProp,
...rest
} = props;
const labelId = React.useId();
const sectionLabelledBy = props["aria-labelledby"] ?? (props["aria-label"] ? void 0 : labelId);
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}error-region-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) => !prevItemsSet.has(item.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,
{
...rest,
"aria-labelledby": sectionLabelledBy,
className: cx("\u{1F95D}-error-region", props.className),
"data-kiwi-visible": !!label,
"data-kiwi-expanded": open,
ref: forwardedRef,
children: /* @__PURE__ */ jsxs("div", { className: "\u{1F95D}-error-region-container", ref: containerRef, children: [
/* @__PURE__ */ jsxs(
DialogDisclosure,
{
className: "\u{1F95D}-error-region-header",
render: /* @__PURE__ */ jsx(Button, { variant: "ghost" }),
children: [
/* @__PURE__ */ jsx(StatusIcon, { tone: "attention", className: "\u{1F95D}-error-region-icon" }),
/* @__PURE__ */ jsx(
Text,
{
render: /* @__PURE__ */ jsx("span", {}),
id: labelId,
className: "\u{1F95D}-error-region-label",
variant: "body-sm",
children: label
}
),
/* @__PURE__ */ jsx(IconButtonPresentation, { inert: true, variant: "ghost", children: /* @__PURE__ */ jsx(ChevronDown, {}) })
]
}
),
/* @__PURE__ */ jsx(
Dialog,
{
className: "\u{1F95D}-error-region-dialog",
portal: false,
modal: false,
autoFocusOnShow: false,
"aria-labelledby": labelId,
children: /* @__PURE__ */ jsx(
Collection,
{
store,
className: "\u{1F95D}-error-region-items",
role: "list",
children: items
}
)
}
)
] })
}
) })
] });
}
);
DEV: ErrorRegionRoot.displayName = "ErrorRegion.Root";
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}-error-region-item", props.className),
ref: forwardedRef,
children: [
/* @__PURE__ */ jsx(Text, { id: messageId, variant: "body-sm", children: message }),
/* @__PURE__ */ jsx("div", { className: "\u{1F95D}-error-region-item-actions", children: actions })
]
}
);
}
);
DEV: ErrorRegionItem.displayName = "ErrorRegion.Item";
export {
ErrorRegionItem as Item,
ErrorRegionRoot as Root
};