{
+ * renders inside the primary link or button.
*/
endContent?: ReactNode;
+ /**
@@ -742,17 +959,17 @@ index a05ba4e..c9a10bc 100644
+ */
+ trailingAction?: ReactNode;
/**
- * Sub-items for nesting.
- */
-@@ -385,6 +391,7 @@ export function SideNavItem({
+ * Row-level secondary controls (icon buttons, menus) rendered as siblings
+ * of the primary element at the trailing edge of the row — after the
+@@ -432,6 +438,7 @@ export function SideNavItem({
href,
onClick,
endContent,
+ trailingAction,
+ actions,
children,
collapsible: itemCollapsible,
- size = 'md',
-@@ -702,6 +709,7 @@ export function SideNavItem({
+@@ -792,6 +799,7 @@ export function SideNavItem({
const item = (
{itemElement}
@@ -964,152 +1181,3 @@ index 55b441e..7aa4174 100644
+ snapToGraphemeBoundary(targetText, renderedPresentation.displayedLen),
+ );
}
-diff --git a/node_modules/@astryxdesign/core/dist/Chat/useTriggerMenu.js b/node_modules/@astryxdesign/core/dist/Chat/useTriggerMenu.js
-index e1d2ebd6c..d4bb8cb03 100644
---- a/node_modules/@astryxdesign/core/dist/Chat/useTriggerMenu.js
-+++ b/node_modules/@astryxdesign/core/dist/Chat/useTriggerMenu.js
-@@ -49,0 +50,39 @@ const styles = {
-+const blockDisplays = new Set(['block', 'flex', 'flow-root', 'grid', 'list-item', 'table']);
-+function createsLineBoundary(node) {
-+ return node instanceof HTMLBRElement || node instanceof HTMLElement && blockDisplays.has(window.getComputedStyle(node).display);
-+}
-+function getTrailingContextCharacter(node) {
-+ if (node.nodeType === Node.TEXT_NODE) {
-+ return (node.textContent ?? '').slice(-1);
-+ }
-+ if (createsLineBoundary(node)) {
-+ return '\n';
-+ }
-+ for (let child = node.lastChild; child; child = child.previousSibling) {
-+ const character = getTrailingContextCharacter(child);
-+ if (character) {
-+ return character;
-+ }
-+ }
-+ return '';
-+}
-+function getCharacterBeforeNode(editable, node) {
-+ let current = node;
-+ while (current && current !== editable) {
-+ for (let sibling = current.previousSibling; sibling; sibling = sibling.previousSibling) {
-+ const character = getTrailingContextCharacter(sibling);
-+ if (character) {
-+ return character;
-+ }
-+ }
-+ const parent = current.parentNode;
-+ if (!parent || parent === editable) {
-+ return '';
-+ }
-+ if (createsLineBoundary(parent)) {
-+ return '\n';
-+ }
-+ current = parent;
-+ }
-+ return '';
-+}
-@@ -64 +103,6 @@ function getTextBeforeCursor(editable) {
-- return (node.textContent ?? '').slice(0, range.startOffset);
-+ const nodeText = (node.textContent ?? '').slice(0, range.startOffset);
-+ const prefix = getCharacterBeforeNode(editable, node);
-+ return {
-+ text: prefix + nodeText,
-+ nodeStart: prefix.length
-+ };
-@@ -309,2 +353,2 @@ export function useTriggerMenu(options) {
-- const textBefore = getTextBeforeCursor(editable);
-- if (textBefore === null) {
-+ const cursorContext = getTextBeforeCursor(editable);
-+ if (cursorContext === null) {
-@@ -316,2 +360,2 @@ export function useTriggerMenu(options) {
-- const found = findActiveTrigger(textBefore, triggers);
-- if (!found) {
-+ const found = findActiveTrigger(cursorContext.text, triggers);
-+ if (!found || found.triggerStart < cursorContext.nodeStart) {
-@@ -322,9 +366,9 @@ export function useTriggerMenu(options) {
- }
- const {
- trigger,
-- query,
-- triggerStart
-+ query
- } = found;
-+ const triggerStart = found.triggerStart - cursorContext.nodeStart;
- if (!state.isActive || state.activeTrigger !== trigger) {
- triggerStartRef.current = triggerStart;
- setState(prev => ({
-diff --git a/node_modules/@astryxdesign/core/src/Chat/useTriggerMenu.tsx b/node_modules/@astryxdesign/core/src/Chat/useTriggerMenu.tsx
-index 6eefd4a59..17071f1b2 100644
---- a/node_modules/@astryxdesign/core/src/Chat/useTriggerMenu.tsx
-+++ b/node_modules/@astryxdesign/core/src/Chat/useTriggerMenu.tsx
-@@ -170 +170,50 @@ const styles = stylex.create({
--function getTextBeforeCursor(editable: HTMLDivElement): string | null {
-+const blockDisplays = new Set(['block', 'flex', 'flow-root', 'grid', 'list-item', 'table']);
-+
-+function createsLineBoundary(node: Node): boolean {
-+ return (
-+ node instanceof HTMLBRElement ||
-+ (node instanceof HTMLElement && blockDisplays.has(window.getComputedStyle(node).display))
-+ );
-+}
-+
-+function getTrailingContextCharacter(node: Node): string {
-+ if (node.nodeType === Node.TEXT_NODE) {
-+ return (node.textContent ?? '').slice(-1);
-+ }
-+ if (createsLineBoundary(node)) {
-+ return '\n';
-+ }
-+ for (let child = node.lastChild; child; child = child.previousSibling) {
-+ const character = getTrailingContextCharacter(child);
-+ if (character) {
-+ return character;
-+ }
-+ }
-+ return '';
-+}
-+
-+function getCharacterBeforeNode(editable: HTMLDivElement, node: Node): string {
-+ let current: Node | null = node;
-+ while (current && current !== editable) {
-+ for (let sibling = current.previousSibling; sibling; sibling = sibling.previousSibling) {
-+ const character = getTrailingContextCharacter(sibling);
-+ if (character) {
-+ return character;
-+ }
-+ }
-+
-+ const parent = current.parentNode;
-+ if (!parent || parent === editable) {
-+ return '';
-+ }
-+ if (createsLineBoundary(parent)) {
-+ return '\n';
-+ }
-+ current = parent;
-+ }
-+ return '';
-+}
-+
-+function getTextBeforeCursor(
-+ editable: HTMLDivElement,
-+): {text: string; nodeStart: number} | null {
-@@ -186 +235,3 @@ function getTextBeforeCursor(editable: HTMLDivElement): string | null {
-- return (node.textContent ?? '').slice(0, range.startOffset);
-+ const nodeText = (node.textContent ?? '').slice(0, range.startOffset);
-+ const prefix = getCharacterBeforeNode(editable, node);
-+ return {text: prefix + nodeText, nodeStart: prefix.length};
-@@ -489,2 +540,2 @@ export function useTriggerMenu(
-- const textBefore = getTextBeforeCursor(editable);
-- if (textBefore === null) {
-+ const cursorContext = getTextBeforeCursor(editable);
-+ if (cursorContext === null) {
-@@ -497,2 +548,2 @@ export function useTriggerMenu(
-- const found = findActiveTrigger(textBefore, triggers);
-- if (!found) {
-+ const found = findActiveTrigger(cursorContext.text, triggers);
-+ if (!found || found.triggerStart < cursorContext.nodeStart) {
-@@ -505 +556,2 @@ export function useTriggerMenu(
-- const {trigger, query, triggerStart} = found;
-+ const {trigger, query} = found;
-+ const triggerStart = found.triggerStart - cursorContext.nodeStart;
diff --git a/scripts/generate-third-party-notices.mjs b/scripts/generate-third-party-notices.mjs
index bd4d713427..9cfa3d05de 100644
--- a/scripts/generate-third-party-notices.mjs
+++ b/scripts/generate-third-party-notices.mjs
@@ -144,6 +144,7 @@ const MIT_COPYRIGHT_OVERRIDES = new Map([
['@astryxdesign/core@0.4.0', 'Copyright (c) 2026 Meta Platforms, Inc.'],
['@astryxdesign/core@0.4.5', 'Copyright (c) 2026 Meta Platforms, Inc.'],
['@astryxdesign/core@0.5.0', 'Copyright (c) 2026 Meta Platforms, Inc.'],
+ ['@astryxdesign/core@0.5.2', 'Copyright (c) 2026 Meta Platforms, Inc.'],
['@stylexjs/stylex@0.19.0', 'Copyright (c) Meta Platforms, Inc. and affiliates.'],
['@wecom/aibot-node-sdk@1.0.7', 'Copyright (c) WeComTeam contributors'],
[