@assistant-ui/react
Version:
Open-source TypeScript/React library for building production-grade AI chat experiences
320 lines (319 loc) • 9.29 kB
JavaScript
"use client";
import { Primitive } from "../../../utils/Primitive.js";
import { useComposerInputPluginRegistryOptional } from "../ComposerInputPluginContext.js";
import { useTriggerPopoverAriaPublish, useTriggerPopoverRootContext } from "./TriggerPopoverRootContext.js";
import { TriggerPopoverResource } from "./TriggerPopoverResource.js";
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
import { createContext, forwardRef, useContext, useEffect, useEffectEvent, useId, useRef, useState } from "@assistant-ui/tap/react-shim";
import { useAui, useAuiState } from "@assistant-ui/store";
import { useResource } from "@assistant-ui/tap";
import { jsx } from "react/jsx-runtime";
// src/primitives/composer/trigger/TriggerPopover.tsx
const TriggerPopoverScopeContext = createContext(null);
const useTriggerPopoverScopeContext = () => {
const ctx = useContext(TriggerPopoverScopeContext);
if (!ctx) throw new Error("useTriggerPopoverScopeContext must be used within ComposerPrimitive.TriggerPopover");
return ctx;
};
const useTriggerPopoverScopeContextOptional = () => {
return useContext(TriggerPopoverScopeContext);
};
const TriggerBehaviorRegistrationContext = createContext(null);
/** Obtain the registration handle from the parent `<TriggerPopover>`. */
const useTriggerBehaviorRegistration = () => {
const ctx = useContext(TriggerBehaviorRegistrationContext);
if (!ctx) throw new Error("TriggerPopover.Directive / TriggerPopover.Action must be rendered inside ComposerPrimitive.TriggerPopover");
return ctx;
};
/**
* Declares a trigger and renders its popover container. The popover only
* renders its DOM (and children) when the trigger character is active in the
* composer input and a behavior sub-primitive has been registered.
*
* A behavior is contributed by rendering exactly one of
* `<TriggerPopover.Directive>` or `<TriggerPopover.Action>` as a child. Without
* a behavior the trigger stays closed.
*
* Must be placed inside `ComposerPrimitive.TriggerPopoverRoot`.
*
* @example
* ```tsx
* <ComposerPrimitive.TriggerPopover
* char="@"
* adapter={mentionAdapter}
* >
* <ComposerPrimitive.TriggerPopover.Directive formatter={formatter} />
* <ComposerPrimitive.TriggerPopoverCategories>
* {(cats) => cats.map(...)}
* </ComposerPrimitive.TriggerPopoverCategories>
* <ComposerPrimitive.TriggerPopoverItems>
* {(items) => items.map(...)}
* </ComposerPrimitive.TriggerPopoverItems>
* </ComposerPrimitive.TriggerPopover>
* ```
*/
const ComposerPrimitiveTriggerPopover = forwardRef((t0, forwardedRef) => {
const $ = c(70);
let adapter;
let ariaLabel;
let char;
let children;
let matcher;
let props;
let t1;
if ($[0] !== t0) {
({char, matcher, adapter, isLoading: t1, "aria-label": ariaLabel, children, ...props} = t0);
$[0] = t0;
$[1] = adapter;
$[2] = ariaLabel;
$[3] = char;
$[4] = children;
$[5] = matcher;
$[6] = props;
$[7] = t1;
} else {
adapter = $[1];
ariaLabel = $[2];
char = $[3];
children = $[4];
matcher = $[5];
props = $[6];
t1 = $[7];
}
const isLoading = t1 === void 0 ? false : t1;
const aui = useAui();
const text = useAuiState(_temp);
const popoverId = useId();
const matcherRef = useRef(matcher);
let t2;
if ($[8] !== matcher) {
t2 = () => {
matcherRef.current = matcher;
};
$[8] = matcher;
$[9] = t2;
} else t2 = $[9];
useEffect(t2);
let t3;
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
t3 = () => (nextText, triggerChar, cursorPosition) => matcherRef.current(nextText, triggerChar, cursorPosition);
$[10] = t3;
} else t3 = $[10];
const [registeredMatcher] = useState(t3);
const hasMatcher = matcher !== void 0;
const behaviorRef = useRef(null);
const [behavior, setBehavior] = useState(null);
const registrationCountRef = useRef(0);
let t4;
if ($[11] !== char) {
t4 = (next) => {
registrationCountRef.current = registrationCountRef.current + 1;
if (process.env.NODE_ENV !== "production" && registrationCountRef.current > 1) console.warn(`[assistant-ui] TriggerPopover "${char}" received more than one behavior child. Exactly one <TriggerPopover.Directive> or <TriggerPopover.Action> is allowed per TriggerPopover; the last registration wins.`);
behaviorRef.current = next;
setBehavior(next);
return () => {
registrationCountRef.current = Math.max(0, registrationCountRef.current - 1);
if (behaviorRef.current === next) {
behaviorRef.current = null;
setBehavior(null);
}
};
};
$[11] = char;
$[12] = t4;
} else t4 = $[12];
const register = t4;
let t5;
if ($[13] !== register) {
t5 = { register };
$[13] = register;
$[14] = t5;
} else t5 = $[14];
const registration = t5;
const t6 = behavior ?? void 0;
let t7;
if ($[15] !== adapter || $[16] !== aui || $[17] !== char || $[18] !== isLoading || $[19] !== matcher || $[20] !== popoverId || $[21] !== t6 || $[22] !== text) {
t7 = TriggerPopoverResource({
adapter,
text,
triggerChar: char,
matcher,
behavior: t6,
aui,
popoverId,
isLoading
});
$[15] = adapter;
$[16] = aui;
$[17] = char;
$[18] = isLoading;
$[19] = matcher;
$[20] = popoverId;
$[21] = t6;
$[22] = text;
$[23] = t7;
} else t7 = $[23];
const resource = useResource(t7);
let t8;
if ($[24] !== resource) {
t8 = () => resource;
$[24] = resource;
$[25] = t8;
} else t8 = $[25];
const getResource = useEffectEvent(t8);
const root = useTriggerPopoverRootContext();
let t9;
if ($[26] !== behavior || $[27] !== char || $[28] !== getResource || $[29] !== hasMatcher || $[30] !== registeredMatcher || $[31] !== root) {
t9 = () => root.register({
char,
...hasMatcher ? { matcher: registeredMatcher } : {},
...behavior ? { behavior } : {},
resource: getResource()
});
$[26] = behavior;
$[27] = char;
$[28] = getResource;
$[29] = hasMatcher;
$[30] = registeredMatcher;
$[31] = root;
$[32] = t9;
} else t9 = $[32];
let t10;
if ($[33] !== behavior || $[34] !== char || $[35] !== hasMatcher || $[36] !== registeredMatcher || $[37] !== root) {
t10 = [
root,
char,
hasMatcher,
registeredMatcher,
behavior
];
$[33] = behavior;
$[34] = char;
$[35] = hasMatcher;
$[36] = registeredMatcher;
$[37] = root;
$[38] = t10;
} else t10 = $[38];
useEffect(t9, t10);
const pluginRegistry = useComposerInputPluginRegistryOptional();
let t11;
if ($[39] !== getResource || $[40] !== pluginRegistry) {
t11 = () => {
if (!pluginRegistry) return;
return pluginRegistry.register(getResource());
};
$[39] = getResource;
$[40] = pluginRegistry;
$[41] = t11;
} else t11 = $[41];
let t12;
if ($[42] !== pluginRegistry) {
t12 = [pluginRegistry];
$[42] = pluginRegistry;
$[43] = t12;
} else t12 = $[43];
useEffect(t11, t12);
const open = behavior !== null && resource.open;
const aria = useTriggerPopoverAriaPublish();
let t13;
let t14;
if ($[44] !== aria || $[45] !== char || $[46] !== open) {
t13 = () => {
if (!open) return;
return () => {
aria.setActiveAria(char, null);
};
};
t14 = [
aria,
char,
open
];
$[44] = aria;
$[45] = char;
$[46] = open;
$[47] = t13;
$[48] = t14;
} else {
t13 = $[47];
t14 = $[48];
}
useEffect(t13, t14);
let t15;
let t16;
if ($[49] !== aria || $[50] !== char || $[51] !== open || $[52] !== popoverId || $[53] !== resource.highlightedItemId) {
t15 = () => {
if (!open) return;
aria.setActiveAria(char, {
popoverId,
highlightedItemId: resource.highlightedItemId
});
};
t16 = [
aria,
char,
popoverId,
open,
resource.highlightedItemId
];
$[49] = aria;
$[50] = char;
$[51] = open;
$[52] = popoverId;
$[53] = resource.highlightedItemId;
$[54] = t15;
$[55] = t16;
} else {
t15 = $[54];
t16 = $[55];
}
useEffect(t15, t16);
let t17;
if ($[56] !== ariaLabel || $[57] !== children || $[58] !== forwardedRef || $[59] !== open || $[60] !== popoverId || $[61] !== props || $[62] !== resource.highlightedItemId) {
t17 = open ? /* @__PURE__ */ jsx(Primitive.div, {
role: "listbox",
id: popoverId,
"aria-label": ariaLabel ?? "Suggestions",
"aria-activedescendant": resource.highlightedItemId,
"data-state": "open",
...props,
ref: forwardedRef,
children
}) : children;
$[56] = ariaLabel;
$[57] = children;
$[58] = forwardedRef;
$[59] = open;
$[60] = popoverId;
$[61] = props;
$[62] = resource.highlightedItemId;
$[63] = t17;
} else t17 = $[63];
let t18;
if ($[64] !== resource || $[65] !== t17) {
t18 = /* @__PURE__ */ jsx(TriggerPopoverScopeContext.Provider, {
value: resource,
children: t17
});
$[64] = resource;
$[65] = t17;
$[66] = t18;
} else t18 = $[66];
let t19;
if ($[67] !== registration || $[68] !== t18) {
t19 = /* @__PURE__ */ jsx(TriggerBehaviorRegistrationContext.Provider, {
value: registration,
children: t18
});
$[67] = registration;
$[68] = t18;
$[69] = t19;
} else t19 = $[69];
return t19;
});
ComposerPrimitiveTriggerPopover.displayName = "ComposerPrimitive.TriggerPopover";
function _temp(s) {
return s.composer.text;
}
export { ComposerPrimitiveTriggerPopover, useTriggerBehaviorRegistration, useTriggerPopoverScopeContext, useTriggerPopoverScopeContextOptional };
//# sourceMappingURL=TriggerPopover.js.map