@stratakit/structures
Version:
Medium-sized component structures for the Strata design system
187 lines (186 loc) • 5.66 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Role } from "@ariakit/react/role";
import { IconButton, Text } from "@stratakit/bricks";
import { GhostAligner } from "@stratakit/bricks/secret-internals";
import { Icon } from "@stratakit/foundations";
import {
forwardRef,
useSafeContext
} from "@stratakit/foundations/secret-internals";
import cx from "classnames";
import { createStore, useStore } from "zustand";
import { combine } from "zustand/middleware";
import { Dismiss, StatusIcon } from "./~utils.icons.js";
import { useInit } from "./~utils.useInit.js";
function createBannerStore(initialState) {
return createStore(
combine(initialState, (set, _, store) => ({
setLabelId: (labelId) => {
set({ labelId: labelId || store.getInitialState().labelId });
}
}))
);
}
const BannerContext = React.createContext(void 0);
function BannerProvider(props) {
const { tone } = props;
const [store] = React.useState(() => createBannerStore({ tone }));
React.useEffect(
function synchronizeWithProps() {
store.setState({ tone });
},
[store, tone]
);
return /* @__PURE__ */ jsx(BannerContext.Provider, { value: store, children: props.children });
}
function useBannerState(selectorFn) {
const store = useSafeContext(BannerContext);
return useStore(store, selectorFn);
}
const BannerRoot = forwardRef((props, forwardedRef) => {
useInit();
const { tone = "neutral", variant = "outline", ...rest } = props;
return /* @__PURE__ */ jsx(BannerProvider, { tone, children: /* @__PURE__ */ jsx(
Role,
{
...rest,
"data-_sk-tone": tone,
"data-_sk-variant": variant,
className: cx("\u{1F95D}Banner", props.className),
ref: forwardedRef
}
) });
});
DEV: BannerRoot.displayName = "Banner.Root";
const BannerIcon = forwardRef((props, forwardedRef) => {
const tone = useBannerState((state) => state.tone);
const hasDefaultIcon = props.href === void 0 && tone !== "neutral";
const {
render = hasDefaultIcon ? /* @__PURE__ */ jsx(StatusIcon, { tone }) : void 0,
...rest
} = props;
return /* @__PURE__ */ jsx(
Icon,
{
...rest,
render,
className: cx("\u{1F95D}BannerIcon", props.className),
ref: forwardedRef
}
);
});
DEV: BannerIcon.displayName = "Banner.Icon";
const BannerLabel = forwardRef(
(props, forwardedRef) => {
const defaultLabelId = React.useId();
const labelId = useBannerState((state) => state.labelId);
const setLabelId = useBannerState((state) => state.setLabelId);
const id = props.id ?? defaultLabelId;
React.useEffect(() => {
setLabelId(id);
return () => setLabelId(void 0);
}, [setLabelId, id]);
return /* @__PURE__ */ jsx(
Text,
{
id: labelId,
render: /* @__PURE__ */ jsx("span", {}),
...props,
className: cx("\u{1F95D}BannerLabel", props.className),
variant: "body-sm",
ref: forwardedRef
}
);
}
);
DEV: BannerLabel.displayName = "Banner.Label";
const BannerMessage = forwardRef(
(props, forwardedRef) => {
return /* @__PURE__ */ jsx(
Text,
{
...props,
variant: "body-sm",
className: cx("\u{1F95D}BannerMessage", props.className),
ref: forwardedRef
}
);
}
);
DEV: BannerMessage.displayName = "Banner.Message";
const BannerActions = forwardRef(
(props, forwardedRef) => {
return /* @__PURE__ */ jsx(
Role.div,
{
...props,
className: cx("\u{1F95D}BannerActions", props.className),
ref: forwardedRef
}
);
}
);
DEV: BannerActions.displayName = "Banner.Actions";
const BannerDismissButton = forwardRef(
(props, forwardedRef) => {
const { label = "Dismiss", ...rest } = props;
const labelId = useBannerState((state) => state.labelId);
const defaultId = React.useId();
const id = props.id ?? defaultId;
return /* @__PURE__ */ jsx(GhostAligner, { align: "block", children: /* @__PURE__ */ jsx(
IconButton,
{
...rest,
id,
className: cx("\u{1F95D}BannerDismissButton", props.className),
variant: "ghost",
label,
"aria-labelledby": `${id} ${labelId || ""}`,
icon: /* @__PURE__ */ jsx(Dismiss, {}),
ref: forwardedRef
}
) });
}
);
DEV: BannerDismissButton.displayName = "Banner.DismissButton";
const Banner = forwardRef((props, forwardedRef) => {
useInit();
const {
message,
label,
actions,
onDismiss,
icon,
tone = "neutral",
...rest
} = props;
const shouldRenderIcon = React.useMemo(
() => icon !== void 0 || tone !== "neutral",
[icon, tone]
);
return /* @__PURE__ */ jsxs(BannerRoot, { tone, ...rest, ref: forwardedRef, children: [
shouldRenderIcon ? /* @__PURE__ */ jsx(
BannerIcon,
{
href: typeof icon === "string" ? icon : void 0,
render: React.isValidElement(icon) ? icon : void 0
}
) : null,
/* @__PURE__ */ jsx(BannerLabel, { render: React.isValidElement(label) ? label : void 0, children: label }),
/* @__PURE__ */ jsx(BannerMessage, { children: message }),
actions != null ? /* @__PURE__ */ jsx(BannerActions, { children: actions }) : null,
onDismiss ? /* @__PURE__ */ jsx(BannerDismissButton, { onClick: onDismiss }) : null
] });
});
DEV: Banner.displayName = "Banner";
var Banner_default = Banner;
export {
BannerActions as Actions,
BannerDismissButton as DismissButton,
BannerIcon as Icon,
BannerLabel as Label,
BannerMessage as Message,
BannerRoot as Root,
Banner_default as default
};