@agentiffai/design 1.3.10 → 1.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -332,6 +332,8 @@ interface UserMessageProps {
332
332
  isStreaming?: boolean;
333
333
  /** Action buttons to display below the message */
334
334
  actions?: ActionButtonType[];
335
+ /** Whether to enable markdown rendering */
336
+ enableMarkdown?: boolean;
335
337
  }
336
338
  /**
337
339
  * UserMessage component displays a user's message in a chat interface.
@@ -345,7 +347,7 @@ interface UserMessageProps {
345
347
  * - Action buttons support
346
348
  * - Avatar display
347
349
  */
348
- declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
350
+ declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, enableMarkdown, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
349
351
 
350
352
  interface ResponseProps {
351
353
  /** Loading state - shows animated dots */
@@ -407,6 +409,7 @@ declare const StreamErrorMessage: React__default.FC<StreamErrorMessageProps>;
407
409
  * StreamingText Component
408
410
  *
409
411
  * Provides typewriter animation for streaming AI responses.
412
+ * Supports basic markdown rendering (bold, italic, code, links).
410
413
  *
411
414
  * @see specs/015-restyle-ai-chat/spec.md:FR-031, FR-042
412
415
  * @see UI_COMPONENTS_SSE.md:548-595
@@ -332,6 +332,8 @@ interface UserMessageProps {
332
332
  isStreaming?: boolean;
333
333
  /** Action buttons to display below the message */
334
334
  actions?: ActionButtonType[];
335
+ /** Whether to enable markdown rendering */
336
+ enableMarkdown?: boolean;
335
337
  }
336
338
  /**
337
339
  * UserMessage component displays a user's message in a chat interface.
@@ -345,7 +347,7 @@ interface UserMessageProps {
345
347
  * - Action buttons support
346
348
  * - Avatar display
347
349
  */
348
- declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
350
+ declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, enableMarkdown, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
349
351
 
350
352
  interface ResponseProps {
351
353
  /** Loading state - shows animated dots */
@@ -407,6 +409,7 @@ declare const StreamErrorMessage: React__default.FC<StreamErrorMessageProps>;
407
409
  * StreamingText Component
408
410
  *
409
411
  * Provides typewriter animation for streaming AI responses.
412
+ * Supports basic markdown rendering (bold, italic, code, links).
410
413
  *
411
414
  * @see specs/015-restyle-ai-chat/spec.md:FR-031, FR-042
412
415
  * @see UI_COMPONENTS_SSE.md:548-595
@@ -110,7 +110,9 @@ var tokens = {
110
110
  fontWeight: {
111
111
  regular: 400,
112
112
  medium: 500,
113
- semibold: 600},
113
+ semibold: 600,
114
+ bold: 700
115
+ },
114
116
  lineHeight: {
115
117
  tight: 1.25,
116
118
  normal: 1.5}
@@ -828,6 +830,59 @@ function AssistantThinking({
828
830
  );
829
831
  }
830
832
  AssistantThinking.displayName = "AssistantThinking";
833
+ function parseMarkdown(text) {
834
+ if (!text) return [];
835
+ const elements = [];
836
+ let key = 0;
837
+ const paragraphs = text.split(/\n\n+/);
838
+ paragraphs.forEach((paragraph, pIndex) => {
839
+ if (pIndex > 0) {
840
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
841
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
842
+ }
843
+ const lines = paragraph.split("\n");
844
+ lines.forEach((line, lineIndex) => {
845
+ if (lineIndex > 0) {
846
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
847
+ }
848
+ const parsed = parseInlineMarkdown(line, key);
849
+ elements.push(...parsed.elements);
850
+ key = parsed.nextKey;
851
+ });
852
+ });
853
+ return elements;
854
+ }
855
+ function parseInlineMarkdown(text, startKey) {
856
+ const elements = [];
857
+ let key = startKey;
858
+ const inlineRegex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`([^`]+)`)|(\[([^\]]+)\]\(([^)]+)\))/g;
859
+ let lastIndex = 0;
860
+ let match;
861
+ while ((match = inlineRegex.exec(text)) !== null) {
862
+ if (match.index > lastIndex) {
863
+ elements.push(text.slice(lastIndex, match.index));
864
+ }
865
+ if (match[1]) {
866
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("strong", { children: match[2] }, key++));
867
+ } else if (match[3]) {
868
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("em", { children: match[4] }, key++));
869
+ } else if (match[5]) {
870
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("code", { children: match[6] }, key++));
871
+ } else if (match[7]) {
872
+ elements.push(
873
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: match[9], target: "_blank", rel: "noopener noreferrer", children: match[8] }, key++)
874
+ );
875
+ }
876
+ lastIndex = match.index + match[0].length;
877
+ }
878
+ if (lastIndex < text.length) {
879
+ elements.push(text.slice(lastIndex));
880
+ }
881
+ if (elements.length === 0) {
882
+ elements.push(text);
883
+ }
884
+ return { elements, nextKey: key };
885
+ }
831
886
  var Container3 = styled8__default.default.div`
832
887
  font-family: ${(props) => props.$variant === "code" ? tokens.typography.fontFamily.monospace : tokens.typography.fontFamily.primary};
833
888
  white-space: pre-wrap;
@@ -836,6 +891,33 @@ var Container3 = styled8__default.default.div`
836
891
  /* Performance optimizations for streaming text */
837
892
  text-rendering: optimizeSpeed;
838
893
  contain: content;
894
+
895
+ /* Markdown element styles */
896
+ strong {
897
+ font-weight: ${tokens.typography.fontWeight.bold};
898
+ color: ${tokens.colors.text.primary};
899
+ }
900
+
901
+ em {
902
+ font-style: italic;
903
+ }
904
+
905
+ code {
906
+ font-family: ${tokens.typography.fontFamily.monospace};
907
+ background: ${tokens.colors.surface.overlay};
908
+ padding: 0.15em 0.4em;
909
+ border-radius: ${tokens.borderRadius.sm};
910
+ font-size: 0.9em;
911
+ }
912
+
913
+ a {
914
+ color: ${tokens.colors.primary};
915
+ text-decoration: none;
916
+
917
+ &:hover {
918
+ text-decoration: underline;
919
+ }
920
+ }
839
921
  `;
840
922
  var Cursor = styled8__default.default.span`
841
923
  display: inline-block;
@@ -880,8 +962,14 @@ var StreamingTextBase = ({
880
962
  wasStreamingRef.current = isStreaming;
881
963
  }, [isStreaming, onStreamComplete]);
882
964
  const showCursor = isStreaming && cursor;
965
+ const renderedContent = react.useMemo(() => {
966
+ if (variant === "markdown") {
967
+ return parseMarkdown(content);
968
+ }
969
+ return content;
970
+ }, [content, variant]);
883
971
  return /* @__PURE__ */ jsxRuntime.jsxs(Container3, { $variant: variant, className, children: [
884
- content,
972
+ renderedContent,
885
973
  showCursor && /* @__PURE__ */ jsxRuntime.jsx(Cursor, {})
886
974
  ] });
887
975
  };
@@ -3646,27 +3734,6 @@ var ActionsContainer3 = styled8__default.default.div`
3646
3734
  gap: ${tokens.spacing.xs};
3647
3735
  flex-wrap: wrap;
3648
3736
  `;
3649
- var StreamingIndicator2 = styled8__default.default.span`
3650
- display: inline-block;
3651
- width: ${tokens.spacing.xs};
3652
- height: ${tokens.spacing.xs};
3653
- margin-left: ${tokens.spacing.xs};
3654
- background-color: ${tokens.colors.text.tertiary};
3655
- border-radius: ${tokens.borderRadius.full};
3656
- animation: pulse 1.5s ease-in-out infinite;
3657
-
3658
- @keyframes pulse {
3659
- 0%,
3660
- 100% {
3661
- opacity: 0.3;
3662
- transform: scale(0.8);
3663
- }
3664
- 50% {
3665
- opacity: 1;
3666
- transform: scale(1.2);
3667
- }
3668
- }
3669
- `;
3670
3737
  var Avatar3 = styled8__default.default.img`
3671
3738
  width: ${tokens.spacing.xl};
3672
3739
  height: ${tokens.spacing.xl};
@@ -3682,15 +3749,21 @@ var UserMessage2 = ({
3682
3749
  avatarUrl,
3683
3750
  username,
3684
3751
  isStreaming = false,
3685
- actions = []
3752
+ actions = [],
3753
+ enableMarkdown = true
3686
3754
  }) => {
3687
3755
  return /* @__PURE__ */ jsxRuntime.jsxs(StyledUserMessage2, { className, children: [
3688
3756
  /* @__PURE__ */ jsxRuntime.jsxs(MessageBubble, { children: [
3689
3757
  username && /* @__PURE__ */ jsxRuntime.jsx("strong", { children: username }),
3690
- /* @__PURE__ */ jsxRuntime.jsxs(MessageContent2, { children: [
3691
- content,
3692
- isStreaming && /* @__PURE__ */ jsxRuntime.jsx(StreamingIndicator2, {})
3693
- ] }),
3758
+ /* @__PURE__ */ jsxRuntime.jsx(MessageContent2, { children: /* @__PURE__ */ jsxRuntime.jsx(
3759
+ StreamingText2,
3760
+ {
3761
+ content,
3762
+ isStreaming,
3763
+ variant: enableMarkdown ? "markdown" : "default",
3764
+ cursor: false
3765
+ }
3766
+ ) }),
3694
3767
  timestamp && /* @__PURE__ */ jsxRuntime.jsx(MessageTime2, { children: timestamp }),
3695
3768
  actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ActionsContainer3, { children: actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsxs(ActionButton3, { onClick: action.onClick, children: [
3696
3769
  action.icon,