UNPKG

@stratakit/structures

Version:

Medium-sized component structures for the Strata design system

174 lines (173 loc) 5.14 kB
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"; 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 [store] = React.useState( () => createBannerStore({ tone: props.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) => { const { tone = "neutral", variant = "outline", ...rest } = props; return /* @__PURE__ */ jsx(BannerProvider, { tone, children: /* @__PURE__ */ jsx( Role, { ...rest, "data-kiwi-tone": tone, "data-kiwi-variant": variant, className: cx("\u{1F95D}-banner", props.className), ref: forwardedRef } ) }); }); 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}-banner-icon", props.className), ref: forwardedRef } ); }); 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}-banner-label", props.className), variant: "body-sm", ref: forwardedRef } ); } ); const BannerMessage = forwardRef( (props, forwardedRef) => { return /* @__PURE__ */ jsx( Text, { ...props, variant: "body-sm", className: cx("\u{1F95D}-banner-message", props.className), ref: forwardedRef } ); } ); const BannerActions = forwardRef( (props, forwardedRef) => { return /* @__PURE__ */ jsx( Role.div, { ...props, className: cx("\u{1F95D}-banner-actions", props.className), ref: forwardedRef } ); } ); 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}-banner-dismiss-button", props.className), variant: "ghost", label, "aria-labelledby": `${id} ${labelId || ""}`, icon: /* @__PURE__ */ jsx(Dismiss, {}), ref: forwardedRef } ) }); } ); const Banner = forwardRef((props, forwardedRef) => { 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 ] }); }); 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 };