entangle-ui 0.6.3 → 0.7.0

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/esm/assets/src/components/editor/ChatPanel/{ChatPanel.css.ts.vanilla-DPIGnZ4A.css → ChatPanel.css.ts.vanilla-BI5569ZO.css} +81 -1
  3. package/dist/esm/assets/src/components/feedback/EmptyState/EmptyState.css.ts.vanilla-B_TWsTOW.css +58 -0
  4. package/dist/esm/assets/src/components/feedback/Spinner/Spinner.css.ts.vanilla-DEUewqdK.css +80 -0
  5. package/dist/esm/assets/src/components/layout/Divider/Divider.css.ts.vanilla-CPvd_RW9.css +72 -0
  6. package/dist/esm/assets/src/components/layout/ListItem/ListItem.css.ts.vanilla-BwAZrX2f.css +68 -0
  7. package/dist/esm/assets/src/components/layout/PageHeader/PageHeader.css.ts.vanilla-DdbyyWAN.css +70 -0
  8. package/dist/esm/assets/src/components/layout/SplitPane/{SplitPane.css.ts.vanilla-BFxdvwyI.css → SplitPane.css.ts.vanilla-BGFZ7zDa.css} +5 -0
  9. package/dist/esm/assets/src/components/primitives/Badge/Badge.css.ts.vanilla-DxCUcxYW.css +95 -0
  10. package/dist/esm/assets/src/components/primitives/Code/Code.css.ts.vanilla-mayBqLDM.css +19 -0
  11. package/dist/esm/assets/src/components/primitives/TextArea/TextArea.css.ts.vanilla-DTOMjGkp.css +85 -0
  12. package/dist/esm/assets/src/theme/{darkTheme.css.ts.vanilla-DCe89yCJ.css → darkTheme.css.ts.vanilla-ab1WD4dr.css} +3 -0
  13. package/dist/esm/assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css +21 -0
  14. package/dist/esm/assets/src/utils/animations.css.ts.vanilla-DOVlpljP.css +58 -0
  15. package/dist/esm/components/editor/ChatPanel/ChatInput.js +18 -7
  16. package/dist/esm/components/editor/ChatPanel/ChatInput.js.map +1 -1
  17. package/dist/esm/components/editor/ChatPanel/ChatMarkdownRenderer.js +268 -0
  18. package/dist/esm/components/editor/ChatPanel/ChatMarkdownRenderer.js.map +1 -0
  19. package/dist/esm/components/editor/ChatPanel/ChatMessage.js +15 -3
  20. package/dist/esm/components/editor/ChatPanel/ChatMessage.js.map +1 -1
  21. package/dist/esm/components/editor/ChatPanel/ChatMessageList.js +19 -5
  22. package/dist/esm/components/editor/ChatPanel/ChatMessageList.js.map +1 -1
  23. package/dist/esm/components/editor/ChatPanel/ChatPanel.css.js +14 -2
  24. package/dist/esm/components/editor/ChatPanel/ChatPanel.css.js.map +1 -1
  25. package/dist/esm/components/editor/ChatPanel/ChatPanel.js +15 -3
  26. package/dist/esm/components/editor/ChatPanel/ChatPanel.js.map +1 -1
  27. package/dist/esm/components/editor/ChatPanel/useChatInput.js +3 -3
  28. package/dist/esm/components/editor/ChatPanel/useChatInput.js.map +1 -1
  29. package/dist/esm/components/editor/ChatPanel/useChatScroll.js +59 -2
  30. package/dist/esm/components/editor/ChatPanel/useChatScroll.js.map +1 -1
  31. package/dist/esm/components/feedback/EmptyState/EmptyState.css.js +13 -0
  32. package/dist/esm/components/feedback/EmptyState/EmptyState.css.js.map +1 -0
  33. package/dist/esm/components/feedback/EmptyState/EmptyState.js +43 -0
  34. package/dist/esm/components/feedback/EmptyState/EmptyState.js.map +1 -0
  35. package/dist/esm/components/feedback/Spinner/Spinner.css.js +16 -0
  36. package/dist/esm/components/feedback/Spinner/Spinner.css.js.map +1 -0
  37. package/dist/esm/components/feedback/Spinner/Spinner.js +50 -0
  38. package/dist/esm/components/feedback/Spinner/Spinner.js.map +1 -0
  39. package/dist/esm/components/layout/Divider/Divider.css.js +9 -0
  40. package/dist/esm/components/layout/Divider/Divider.css.js.map +1 -0
  41. package/dist/esm/components/layout/Divider/Divider.js +51 -0
  42. package/dist/esm/components/layout/Divider/Divider.js.map +1 -0
  43. package/dist/esm/components/layout/ListItem/ListItem.css.js +10 -0
  44. package/dist/esm/components/layout/ListItem/ListItem.css.js.map +1 -0
  45. package/dist/esm/components/layout/ListItem/ListItem.js +45 -0
  46. package/dist/esm/components/layout/ListItem/ListItem.js.map +1 -0
  47. package/dist/esm/components/layout/PageHeader/PageHeader.css.js +13 -0
  48. package/dist/esm/components/layout/PageHeader/PageHeader.css.js.map +1 -0
  49. package/dist/esm/components/layout/PageHeader/PageHeader.js +29 -0
  50. package/dist/esm/components/layout/PageHeader/PageHeader.js.map +1 -0
  51. package/dist/esm/components/layout/SplitPane/SplitPane.css.js +1 -1
  52. package/dist/esm/components/navigation/Tabs/TabPanel.js +6 -3
  53. package/dist/esm/components/navigation/Tabs/TabPanel.js.map +1 -1
  54. package/dist/esm/components/navigation/Tabs/Tabs.js +3 -1
  55. package/dist/esm/components/navigation/Tabs/Tabs.js.map +1 -1
  56. package/dist/esm/components/primitives/Badge/Badge.css.js +12 -0
  57. package/dist/esm/components/primitives/Badge/Badge.css.js.map +1 -0
  58. package/dist/esm/components/primitives/Badge/Badge.js +67 -0
  59. package/dist/esm/components/primitives/Badge/Badge.js.map +1 -0
  60. package/dist/esm/components/primitives/Code/Code.css.js +7 -0
  61. package/dist/esm/components/primitives/Code/Code.css.js.map +1 -0
  62. package/dist/esm/components/primitives/Code/Code.js +24 -0
  63. package/dist/esm/components/primitives/Code/Code.js.map +1 -0
  64. package/dist/esm/components/primitives/TextArea/TextArea.css.js +10 -0
  65. package/dist/esm/components/primitives/TextArea/TextArea.css.js.map +1 -0
  66. package/dist/esm/components/primitives/TextArea/TextArea.js +97 -0
  67. package/dist/esm/components/primitives/TextArea/TextArea.js.map +1 -0
  68. package/dist/esm/index.js +11 -0
  69. package/dist/esm/index.js.map +1 -1
  70. package/dist/esm/theme/ThemeProvider.js +17 -3
  71. package/dist/esm/theme/ThemeProvider.js.map +1 -1
  72. package/dist/esm/theme/contract.css.js +1 -1
  73. package/dist/esm/theme/darkTheme.css.js +2 -2
  74. package/dist/esm/theme/globalScrollbars.css.js +6 -0
  75. package/dist/esm/theme/globalScrollbars.css.js.map +1 -0
  76. package/dist/esm/utils/animations.css.js +13 -0
  77. package/dist/esm/utils/animations.css.js.map +1 -0
  78. package/dist/types/components/editor/ChatPanel/ChatMarkdownRenderer.d.ts +323 -0
  79. package/dist/types/components/editor/ChatPanel/ChatMarkdownRenderer.types.d.ts +46 -0
  80. package/dist/types/components/editor/ChatPanel/ChatMessage.d.ts +1 -0
  81. package/dist/types/components/editor/ChatPanel/ChatMessageList.d.ts +2 -1
  82. package/dist/types/components/editor/ChatPanel/ChatPanel.d.ts +1 -0
  83. package/dist/types/components/editor/ChatPanel/ChatPanel.types.d.ts +82 -1
  84. package/dist/types/components/feedback/EmptyState/EmptyState.d.ts +313 -0
  85. package/dist/types/components/feedback/EmptyState/EmptyState.types.d.ts +31 -0
  86. package/dist/types/components/feedback/Spinner/Spinner.d.ts +306 -0
  87. package/dist/types/components/feedback/Spinner/Spinner.types.d.ts +41 -0
  88. package/dist/types/components/layout/Divider/Divider.d.ts +307 -0
  89. package/dist/types/components/layout/Divider/Divider.types.d.ts +50 -0
  90. package/dist/types/components/layout/ListItem/ListItem.d.ts +312 -0
  91. package/dist/types/components/layout/ListItem/ListItem.types.d.ts +35 -0
  92. package/dist/types/components/layout/PageHeader/PageHeader.d.ts +311 -0
  93. package/dist/types/components/layout/PageHeader/PageHeader.types.d.ts +30 -0
  94. package/dist/types/components/navigation/Tabs/Tabs.types.d.ts +10 -0
  95. package/dist/types/components/primitives/Badge/Badge.d.ts +310 -0
  96. package/dist/types/components/primitives/Badge/Badge.types.d.ts +67 -0
  97. package/dist/types/components/primitives/Button/Button.d.ts +1 -1
  98. package/dist/types/components/primitives/Code/Code.d.ts +301 -0
  99. package/dist/types/components/primitives/Code/Code.types.d.ts +17 -0
  100. package/dist/types/components/primitives/IconButton/IconButton.d.ts +1 -1
  101. package/dist/types/components/primitives/TextArea/TextArea.d.ts +26 -0
  102. package/dist/types/components/primitives/TextArea/TextArea.types.d.ts +76 -0
  103. package/dist/types/index.d.ts +20 -1
  104. package/dist/types/theme/ThemeProvider.d.ts +14 -2
  105. package/dist/types/theme/contract.css.d.ts +3 -0
  106. package/dist/types/theme/darkTheme.css.d.ts +3 -0
  107. package/dist/types/utils/animations.css.d.ts +18 -0
  108. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import './../../../assets/src/components/editor/ChatPanel/ChatPanel.css.ts.vanilla-DPIGnZ4A.css';
1
+ import './../../../assets/src/components/editor/ChatPanel/ChatPanel.css.ts.vanilla-BI5569ZO.css';
2
2
  import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
3
 
4
4
  var actionBarStyle = 'ChatPanel_actionBarStyle__1c3e77r2b';
@@ -41,12 +41,24 @@ var inputStopButtonStyle = 'ChatPanel_inputStopButtonStyle__1c3e77ru';
41
41
  var inputTextareaStyle = 'ChatPanel_inputTextareaStyle__1c3e77rs';
42
42
  var inputToolbarStyle = 'ChatPanel_inputToolbarStyle__1c3e77rw';
43
43
  var inputWrapperStyle = 'ChatPanel_inputWrapperStyle__1c3e77rr';
44
+ var markdownBlockquoteStyle = 'ChatPanel_markdownBlockquoteStyle__1c3e77r2i';
45
+ var markdownHeadingStyle = 'ChatPanel_markdownHeadingStyle__1c3e77r2e';
46
+ var markdownHrStyle = 'ChatPanel_markdownHrStyle__1c3e77r2j';
47
+ var markdownLinkStyle = 'ChatPanel_markdownLinkStyle__1c3e77r2h';
48
+ var markdownListItemStyle = 'ChatPanel_markdownListItemStyle__1c3e77r2g';
49
+ var markdownListStyle = 'ChatPanel_markdownListStyle__1c3e77r2f';
50
+ var markdownParagraphStyle = 'ChatPanel_markdownParagraphStyle__1c3e77r2d';
51
+ var markdownRootStyle = 'ChatPanel_markdownRootStyle__1c3e77r2c';
52
+ var markdownTableStyle = 'ChatPanel_markdownTableStyle__1c3e77r2k';
53
+ var markdownTdStyle = 'ChatPanel_markdownTdStyle__1c3e77r2m';
54
+ var markdownThStyle = 'ChatPanel_markdownThStyle__1c3e77r2l';
44
55
  var messageAvatarImgStyle = 'ChatPanel_messageAvatarImgStyle__1c3e77rc';
45
56
  var messageAvatarStyle = 'ChatPanel_messageAvatarStyle__1c3e77rb';
46
57
  var messageContentStyle = 'ChatPanel_messageContentStyle__1c3e77ra';
47
58
  var messageErrorCaptionStyle = 'ChatPanel_messageErrorCaptionStyle__1c3e77rl';
48
59
  var messageErrorIconStyle = 'ChatPanel_messageErrorIconStyle__1c3e77rm';
49
60
  var messageListContentStyle = 'ChatPanel_messageListContentStyle__1c3e77r3';
61
+ var messageMaxWidthVarName = '--etui-chat-message-max-width';
50
62
  var messageRecipe = createRuntimeFn({defaultClassName:'ChatPanel_messageRecipe__1c3e77r5',variantClassNames:{role:{user:'ChatPanel_messageRecipe_role_user__1c3e77r6',assistant:'ChatPanel_messageRecipe_role_assistant__1c3e77r7',system:'ChatPanel_messageRecipe_role_system__1c3e77r8',tool:'ChatPanel_messageRecipe_role_tool__1c3e77r9'}},defaultVariants:{role:'assistant'},compoundVariants:[]});
51
63
  var messageTextStyle = 'ChatPanel_messageTextStyle__1c3e77re';
52
64
  var messageTimestampStyle = 'ChatPanel_messageTimestampStyle__1c3e77rd';
@@ -68,5 +80,5 @@ var typingIndicatorStyle = 'ChatPanel_typingIndicatorStyle__1c3e77rz';
68
80
  var typingLabelStyle = 'ChatPanel_typingLabelStyle__1c3e77r13';
69
81
  var typingPulseStyle = 'ChatPanel_typingPulseStyle__1c3e77r12';
70
82
 
71
- export { actionBarStyle, attachmentChipIconStyle, attachmentChipNameStyle, attachmentChipRemoveStyle, attachmentChipStyle, attachmentThumbnailStyle, bubbleErrorStyle, bubbleRecipe, chatPanelRecipe, codeBlockActionsStyle, codeBlockContainerStyle, codeBlockContentStyle, codeBlockContentWithLineNumbersStyle, codeBlockCopyButtonStyle, codeBlockHeaderStyle, codeBlockLanguageStyle, codeBlockLineNumbersColumnStyle, codeBlockMaxHeightVar, codeBlockPreStyle, contextChipDismissStyle, contextChipIconStyle, contextChipItemsStyle, contextChipLabelStyle, contextChipStyle, emptyStateDescriptionStyle, emptyStateIconStyle, emptyStateStyle, emptyStateSuggestionStyle, emptyStateSuggestionsStyle, emptyStateTitleStyle, inputAttachmentsStyle, inputBottomBarStyle, inputButtonStyle, inputContainerStyle, inputMaxHeightVar, inputPrefixStyle, inputStopButtonStyle, inputTextareaStyle, inputToolbarStyle, inputWrapperStyle, messageAvatarImgStyle, messageAvatarStyle, messageContentStyle, messageErrorCaptionStyle, messageErrorIconStyle, messageListContentStyle, messageRecipe, messageTextStyle, messageTimestampStyle, newMessagesBannerStyle, toolCallChevronRecipe, toolCallContainerStyle, toolCallDetailsStyle, toolCallDurationStyle, toolCallErrorStyle, toolCallHeaderStyle, toolCallIconStyle, toolCallNameStyle, toolCallPreStyle, toolCallSectionLabelStyle, toolCallStatusRecipe, typingDotStyle, typingDotsContainerStyle, typingIndicatorStyle, typingLabelStyle, typingPulseStyle };
83
+ export { actionBarStyle, attachmentChipIconStyle, attachmentChipNameStyle, attachmentChipRemoveStyle, attachmentChipStyle, attachmentThumbnailStyle, bubbleErrorStyle, bubbleRecipe, chatPanelRecipe, codeBlockActionsStyle, codeBlockContainerStyle, codeBlockContentStyle, codeBlockContentWithLineNumbersStyle, codeBlockCopyButtonStyle, codeBlockHeaderStyle, codeBlockLanguageStyle, codeBlockLineNumbersColumnStyle, codeBlockMaxHeightVar, codeBlockPreStyle, contextChipDismissStyle, contextChipIconStyle, contextChipItemsStyle, contextChipLabelStyle, contextChipStyle, emptyStateDescriptionStyle, emptyStateIconStyle, emptyStateStyle, emptyStateSuggestionStyle, emptyStateSuggestionsStyle, emptyStateTitleStyle, inputAttachmentsStyle, inputBottomBarStyle, inputButtonStyle, inputContainerStyle, inputMaxHeightVar, inputPrefixStyle, inputStopButtonStyle, inputTextareaStyle, inputToolbarStyle, inputWrapperStyle, markdownBlockquoteStyle, markdownHeadingStyle, markdownHrStyle, markdownLinkStyle, markdownListItemStyle, markdownListStyle, markdownParagraphStyle, markdownRootStyle, markdownTableStyle, markdownTdStyle, markdownThStyle, messageAvatarImgStyle, messageAvatarStyle, messageContentStyle, messageErrorCaptionStyle, messageErrorIconStyle, messageListContentStyle, messageMaxWidthVarName, messageRecipe, messageTextStyle, messageTimestampStyle, newMessagesBannerStyle, toolCallChevronRecipe, toolCallContainerStyle, toolCallDetailsStyle, toolCallDurationStyle, toolCallErrorStyle, toolCallHeaderStyle, toolCallIconStyle, toolCallNameStyle, toolCallPreStyle, toolCallSectionLabelStyle, toolCallStatusRecipe, typingDotStyle, typingDotsContainerStyle, typingIndicatorStyle, typingLabelStyle, typingPulseStyle };
72
84
  //# sourceMappingURL=ChatPanel.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatPanel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ChatPanel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,10 +2,22 @@
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import React from 'react';
4
4
  import { cx } from '../../../utils/cx.js';
5
- import { chatPanelRecipe } from './ChatPanel.css.js';
5
+ import { chatPanelRecipe, messageMaxWidthVarName } from './ChatPanel.css.js';
6
6
 
7
- const ChatPanel = /*#__PURE__*/ React.memo(({ density = 'comfortable', children, className, style, testId, ref, ...rest }) => {
8
- return (jsx("div", { ref: ref, className: cx(chatPanelRecipe({ density }), className), style: style, "data-testid": testId, ...rest, children: children }));
7
+ function resolveMaxWidth(value) {
8
+ if (value === undefined)
9
+ return undefined;
10
+ return typeof value === 'number' ? `${value}px` : value;
11
+ }
12
+ const ChatPanel = /*#__PURE__*/ React.memo(({ density = 'comfortable', messageMaxWidth, children, className, style, testId, ref, ...rest }) => {
13
+ const resolvedMaxWidth = resolveMaxWidth(messageMaxWidth);
14
+ const rootStyle = resolvedMaxWidth
15
+ ? {
16
+ [messageMaxWidthVarName]: resolvedMaxWidth,
17
+ ...style,
18
+ }
19
+ : (style ?? {});
20
+ return (jsx("div", { ref: ref, className: cx(chatPanelRecipe({ density }), className), style: rootStyle, "data-testid": testId, ...rest, children: children }));
9
21
  });
10
22
  ChatPanel.displayName = 'ChatPanel';
11
23
 
@@ -1 +1 @@
1
- {"version":3,"file":"ChatPanel.js","sources":["../../../../../../src/components/editor/ChatPanel/ChatPanel.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAOO;AAUH;AAWF;AAGF;;"}
1
+ {"version":3,"file":"ChatPanel.js","sources":["../../../../../../src/components/editor/ChatPanel/ChatPanel.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAOA;;AAG2B;AACzB;AACF;AAEO;AAWH;;AAEE;;AAEI;AACuB;AAC3B;AAEF;AAWF;AAGF;;"}
@@ -2,7 +2,7 @@
2
2
  import { useState, useRef, useCallback, useEffect } from 'react';
3
3
 
4
4
  function useChatInput(options = {}) {
5
- const { submitKey = 'enter', onSubmit, maxLines = 6 } = options;
5
+ const { submitKey = 'enter', onSubmit, maxLines = 6, attachmentsCount = 0, } = options;
6
6
  const [value, setValue] = useState('');
7
7
  const textareaRef = useRef(null);
8
8
  const autoResize = useCallback(() => {
@@ -40,12 +40,12 @@ function useChatInput(options = {}) {
40
40
  if (isSubmit) {
41
41
  event.preventDefault();
42
42
  const trimmed = value.trim();
43
- if (trimmed) {
43
+ if (trimmed || attachmentsCount > 0) {
44
44
  onSubmit?.(trimmed);
45
45
  clear();
46
46
  }
47
47
  }
48
- }, [submitKey, value, onSubmit, clear]);
48
+ }, [submitKey, value, onSubmit, clear, attachmentsCount]);
49
49
  return {
50
50
  value,
51
51
  setValue,
@@ -1 +1 @@
1
- {"version":3,"file":"useChatInput.js","sources":["../../../../../../src/components/editor/ChatPanel/useChatInput.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAQM;AAGJ;;AAEA;AAEA;AACE;AACA;;;AAGA;AAEA;AAIA;AACA;;AAGF;;;AAIE;AACF;AAEA;;AAEE;;AAEE;;;AAIJ;AAEI;;AAKJ;AAEI;AAEI;;;;AAIA;;;AAIF;;AAEE;AACA;;;;;;;;;;;;AAeV;;"}
1
+ {"version":3,"file":"useChatInput.js","sources":["../../../../../../src/components/editor/ChatPanel/useChatInput.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAQM;AAGJ;;AAOA;AAEA;AACE;AACA;;;AAGA;AAEA;AAIA;AACA;;AAGF;;;AAIE;AACF;AAEA;;AAEE;;AAEE;;;AAIJ;AAEI;;AAKJ;AAEI;AAEI;;;;AAIA;;;AAIF;AACA;AACE;AACA;;;AAGN;;;;;;;;;AAYJ;;"}
@@ -1,12 +1,23 @@
1
1
  "use client";
2
- import { useRef, useState, useCallback, useEffect } from 'react';
2
+ import { useRef, useState, useEffect, useCallback } from 'react';
3
3
 
4
4
  function useChatScroll(options) {
5
5
  const { messages, enabled = true, threshold = 100 } = options;
6
6
  const scrollContainerRef = useRef(null);
7
+ const scrollContentRef = useRef(null);
7
8
  const [isAtBottom, setIsAtBottom] = useState(true);
8
9
  const [hasNewMessages, setHasNewMessages] = useState(false);
9
10
  const prevMessageCountRef = useRef(messages.length);
11
+ const isAtBottomRef = useRef(isAtBottom);
12
+ const enabledRef = useRef(enabled);
13
+ const lastContentHeightRef = useRef(0);
14
+ // Keep refs in sync for use inside observer callbacks.
15
+ useEffect(() => {
16
+ isAtBottomRef.current = isAtBottom;
17
+ }, [isAtBottom]);
18
+ useEffect(() => {
19
+ enabledRef.current = enabled;
20
+ }, [enabled]);
10
21
  const checkIfAtBottom = useCallback(() => {
11
22
  const container = scrollContainerRef.current;
12
23
  if (!container)
@@ -25,6 +36,15 @@ function useChatScroll(options) {
25
36
  setIsAtBottom(true);
26
37
  setHasNewMessages(false);
27
38
  }, []);
39
+ const scrollTo = useCallback((opts) => {
40
+ const container = scrollContainerRef.current;
41
+ if (!container)
42
+ return;
43
+ container.scrollTo(opts);
44
+ }, []);
45
+ const scrollToElement = useCallback((el, opts) => {
46
+ el.scrollIntoView(opts);
47
+ }, []);
28
48
  // Listen for scroll events to track position
29
49
  useEffect(() => {
30
50
  const container = scrollContainerRef.current;
@@ -40,7 +60,41 @@ function useChatScroll(options) {
40
60
  container.addEventListener('scroll', handleScroll, { passive: true });
41
61
  return () => container.removeEventListener('scroll', handleScroll);
42
62
  }, [checkIfAtBottom]);
43
- // Auto-scroll or show indicator on new messages
63
+ // Observe content growth keeps the list pinned to the bottom during streaming
64
+ // (when message text grows but `messages.length` stays constant).
65
+ useEffect(() => {
66
+ if (typeof ResizeObserver === 'undefined')
67
+ return;
68
+ const content = scrollContentRef.current;
69
+ if (!content)
70
+ return;
71
+ lastContentHeightRef.current = content.getBoundingClientRect().height;
72
+ const ro = new ResizeObserver(entries => {
73
+ const entry = entries[0];
74
+ if (!entry)
75
+ return;
76
+ const nextHeight = entry.contentRect.height;
77
+ const prevHeight = lastContentHeightRef.current;
78
+ lastContentHeightRef.current = nextHeight;
79
+ // Only react to growth — shrinks shouldn't force a scroll jump.
80
+ if (nextHeight <= prevHeight)
81
+ return;
82
+ if (!enabledRef.current)
83
+ return;
84
+ if (isAtBottomRef.current) {
85
+ scrollToBottom('auto');
86
+ }
87
+ else {
88
+ setHasNewMessages(true);
89
+ }
90
+ });
91
+ ro.observe(content);
92
+ return () => {
93
+ ro.disconnect();
94
+ };
95
+ }, [scrollToBottom]);
96
+ // Auto-scroll or show indicator on new messages. Fallback for mounts and
97
+ // cleared lists where content height may not grow monotonically.
44
98
  useEffect(() => {
45
99
  const currentCount = messages.length;
46
100
  const prevCount = prevMessageCountRef.current;
@@ -61,9 +115,12 @@ function useChatScroll(options) {
61
115
  }, [messages.length, enabled, isAtBottom, scrollToBottom]);
62
116
  return {
63
117
  scrollContainerRef,
118
+ scrollContentRef,
64
119
  isAtBottom,
65
120
  hasNewMessages,
66
121
  scrollToBottom,
122
+ scrollTo,
123
+ scrollToElement,
67
124
  };
68
125
  }
69
126
 
@@ -1 +1 @@
1
- {"version":3,"file":"useChatScroll.js","sources":["../../../../../../src/components/editor/ChatPanel/useChatScroll.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAQM;AAGJ;AAEA;;;;AAKA;AACE;AACA;AAAgB;;AAGhB;AACF;;AAGE;AACA;;;;;AAKC;;;;;;AAOD;AACA;;;AAGE;;;;;AAKF;AAEA;;AAEF;;;AAIE;AACA;AACA;;;AAIA;;;;;AAKI;AACF;;;;;AAIJ;;;;;;;AAQF;;"}
1
+ {"version":3,"file":"useChatScroll.js","sources":["../../../../../../src/components/editor/ChatPanel/useChatScroll.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAQM;AAGJ;AAEA;AACA;;;;AAIA;AACA;AACA;;;AAIE;AACF;;AAEE;AACF;AAEA;AACE;AACA;AAAgB;;AAGhB;AACF;;AAGE;AACA;;;;;AAKC;;;;AAKH;AACE;AACA;;AACA;;;AAKE;;;;AAOF;AACA;;;AAGE;;;;;AAKF;AAEA;;AAEF;;;;;;AAOE;AACA;;;AAIA;AACE;AACA;;AAEA;AACA;AACA;;;;;;AAMA;;;;;;AAKF;AAEA;AACA;;AAEA;AACF;;;;AAKE;AACA;AACA;;;AAIA;;;;;AAKI;AACF;;;;;AAIJ;;;;;;;;;;AAWF;;"}
@@ -0,0 +1,13 @@
1
+ import './../../../assets/src/components/feedback/EmptyState/EmptyState.css.ts.vanilla-B_TWsTOW.css';
2
+ import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
+
4
+ var emptyStateActionStyle = 'EmptyState_emptyStateActionStyle__1ihe8h18';
5
+ var emptyStateDescriptionStyle = 'EmptyState_emptyStateDescriptionStyle__1ihe8h15';
6
+ var emptyStateIconStyle = 'EmptyState_emptyStateIconStyle__1ihe8h13';
7
+ var emptyStateRecipe = createRuntimeFn({defaultClassName:'EmptyState_emptyStateRecipe__1ihe8h10',variantClassNames:{variant:{'default':'EmptyState_emptyStateRecipe_variant_default__1ihe8h11',compact:'EmptyState_emptyStateRecipe_variant_compact__1ihe8h12'}},defaultVariants:{variant:'default'},compoundVariants:[]});
8
+ var emptyStateTextColumnCompactStyle = 'EmptyState_emptyStateTextColumnCompactStyle__1ihe8h17';
9
+ var emptyStateTextColumnStyle = 'EmptyState_emptyStateTextColumnStyle__1ihe8h16';
10
+ var emptyStateTitleStyle = 'EmptyState_emptyStateTitleStyle__1ihe8h14';
11
+
12
+ export { emptyStateActionStyle, emptyStateDescriptionStyle, emptyStateIconStyle, emptyStateRecipe, emptyStateTextColumnCompactStyle, emptyStateTextColumnStyle, emptyStateTitleStyle };
13
+ //# sourceMappingURL=EmptyState.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import React from 'react';
4
+ import { cx } from '../../../utils/cx.js';
5
+ import { Spinner } from '../Spinner/Spinner.js';
6
+ import { emptyStateIconStyle, emptyStateTextColumnCompactStyle, emptyStateTextColumnStyle, emptyStateTitleStyle, emptyStateDescriptionStyle, emptyStateActionStyle, emptyStateRecipe } from './EmptyState.css.js';
7
+
8
+ /**
9
+ * Generic empty / loading state surface.
10
+ *
11
+ * Use for empty lists, filtered-out results, or "not yet started"
12
+ * placeholders. When `loading` is `true`, a `Spinner` is rendered in
13
+ * place of the icon and the root uses `role="status"`.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <EmptyState
18
+ * icon={<SearchIcon size="lg" />}
19
+ * title="No results"
20
+ * description="Try a different search term."
21
+ * action={<Button>Reset filters</Button>}
22
+ * />
23
+ *
24
+ * <EmptyState loading title="Loading conversation..." />
25
+ * ```
26
+ */
27
+ const EmptyState = /*#__PURE__*/ React.memo(({ icon, title, description, action, variant = 'default', loading = false, className, style, testId, ref, ...rest }) => {
28
+ const textColumnClass = variant === 'compact'
29
+ ? emptyStateTextColumnCompactStyle
30
+ : emptyStateTextColumnStyle;
31
+ const statusAttrs = loading
32
+ ? {
33
+ role: 'status',
34
+ 'aria-live': 'polite',
35
+ }
36
+ : {};
37
+ return (jsxs("div", { ref: ref, className: cx(emptyStateRecipe({ variant }), className), style: style, "data-testid": testId, ...statusAttrs, ...rest, children: [loading ? (jsx("span", { className: emptyStateIconStyle, children: jsx(Spinner, { size: "lg" }) })) : (icon && jsx("span", { className: emptyStateIconStyle, children: icon })), (title !== undefined && title !== null) ||
38
+ (description !== undefined && description !== null) ? (jsxs("div", { className: textColumnClass, children: [title !== undefined && title !== null && (jsx("h3", { className: emptyStateTitleStyle, children: title })), description !== undefined && description !== null && (jsx("p", { className: emptyStateDescriptionStyle, children: description }))] })) : null, action && jsx("div", { className: emptyStateActionStyle, children: action })] }));
39
+ });
40
+ EmptyState.displayName = 'EmptyState';
41
+
42
+ export { EmptyState };
43
+ //# sourceMappingURL=EmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.js","sources":["../../../../../../src/components/feedback/EmptyState/EmptyState.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AAgBA;;;;;;;;;;;;;;;;;;AAkBG;AACI;AAcH;AAEI;;;AAIF;AACI;AACA;AACD;;AAGL;AAkBI;AAcN;AAGF;;"}
@@ -0,0 +1,16 @@
1
+ import './../../../assets/src/utils/animations.css.ts.vanilla-DOVlpljP.css';
2
+ import './../../../assets/src/components/feedback/Spinner/Spinner.css.ts.vanilla-DEUewqdK.css';
3
+ import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
4
+
5
+ var spinnerColorVar = 'var(--spinnerColorVar__670vre0)';
6
+ var spinnerDotRecipe = createRuntimeFn({defaultClassName:'Spinner_spinnerDotRecipe__670vre5',variantClassNames:{delay:{'0':'Spinner_spinnerDotRecipe_delay_0__670vre6','1':'Spinner_spinnerDotRecipe_delay_1__670vre7','2':'Spinner_spinnerDotRecipe_delay_2__670vre8'}},defaultVariants:{},compoundVariants:[]});
7
+ var spinnerDotsSizerStyle = 'Spinner_spinnerDotsSizerStyle__670vre9';
8
+ var spinnerLabelStyle = 'Spinner_spinnerLabelStyle__670vreb';
9
+ var spinnerPulseStyle = 'Spinner_spinnerPulseStyle__670vrea';
10
+ var spinnerRingStyle = 'Spinner_spinnerRingStyle__670vre3';
11
+ var spinnerRootStyle = 'Spinner_spinnerRootStyle__670vre2';
12
+ var spinnerSizeVar = 'var(--spinnerSizeVar__670vre1)';
13
+ var visuallyHiddenStyle = 'Spinner_visuallyHiddenStyle__670vrec';
14
+
15
+ export { spinnerColorVar, spinnerDotRecipe, spinnerDotsSizerStyle, spinnerLabelStyle, spinnerPulseStyle, spinnerRingStyle, spinnerRootStyle, spinnerSizeVar, visuallyHiddenStyle };
16
+ //# sourceMappingURL=Spinner.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import React from 'react';
4
+ import { assignInlineVars } from '@vanilla-extract/dynamic';
5
+ import { vars } from '../../../theme/contract.css.js';
6
+ import { cx } from '../../../utils/cx.js';
7
+ import { spinnerSizeVar, spinnerColorVar, spinnerRingStyle, spinnerPulseStyle, spinnerDotsSizerStyle, spinnerDotRecipe, spinnerLabelStyle, visuallyHiddenStyle, spinnerRootStyle } from './Spinner.css.js';
8
+
9
+ const SIZE_MAP = {
10
+ xs: '12px',
11
+ sm: '14px',
12
+ md: '16px',
13
+ lg: '20px',
14
+ };
15
+ const NAMED_COLOR_MAP = {
16
+ primary: vars.colors.text.primary,
17
+ secondary: vars.colors.text.secondary,
18
+ muted: vars.colors.text.muted,
19
+ accent: vars.colors.accent.primary,
20
+ };
21
+ function resolveColor(color) {
22
+ return NAMED_COLOR_MAP[color] ?? color;
23
+ }
24
+ /**
25
+ * Loading / activity indicator.
26
+ *
27
+ * Announces itself via `role="status"` and `aria-label`; honors
28
+ * `prefers-reduced-motion` by halting animation and dimming the indicator.
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * <Spinner />
33
+ * <Spinner variant="dots" size="lg" />
34
+ * <Spinner showLabel label="Fetching results..." />
35
+ * ```
36
+ */
37
+ const Spinner = /*#__PURE__*/ React.memo(({ size = 'md', variant = 'ring', color = 'accent', label = 'Loading...', showLabel = false, className, style, testId, ref, ...rest }) => {
38
+ const resolvedColor = resolveColor(color);
39
+ const resolvedSize = SIZE_MAP[size];
40
+ const inlineVars = assignInlineVars({
41
+ [spinnerColorVar]: resolvedColor,
42
+ [spinnerSizeVar]: resolvedSize,
43
+ });
44
+ const indicator = variant === 'ring' ? (jsx("span", { className: spinnerRingStyle, "aria-hidden": true })) : variant === 'pulse' ? (jsx("span", { className: spinnerPulseStyle, "aria-hidden": true })) : (jsxs("span", { className: spinnerDotsSizerStyle, "aria-hidden": true, children: [jsx("span", { className: spinnerDotRecipe({ delay: '0' }) }), jsx("span", { className: spinnerDotRecipe({ delay: '1' }) }), jsx("span", { className: spinnerDotRecipe({ delay: '2' }) })] }));
45
+ return (jsxs("span", { ref: ref, role: "status", "aria-live": "polite", "aria-label": label, className: cx(spinnerRootStyle, className), style: { ...inlineVars, ...style }, "data-testid": testId, ...rest, children: [indicator, showLabel ? (jsx("span", { className: spinnerLabelStyle, children: label })) : (jsx("span", { className: visuallyHiddenStyle, children: label }))] }));
46
+ });
47
+ Spinner.displayName = 'Spinner';
48
+
49
+ export { Spinner };
50
+ //# sourceMappingURL=Spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.js","sources":["../../../../../../src/components/feedback/Spinner/Spinner.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;AAmBA;AACE;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;;AAGF;AACE;AACF;AAEA;;;;;;;;;;;;AAYG;;AAcC;AACA;;;;AAKC;AAED;AAaA;AAmBF;AAGF;;"}
@@ -0,0 +1,9 @@
1
+ import './../../../assets/src/components/layout/Divider/Divider.css.ts.vanilla-CPvd_RW9.css';
2
+ import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
+
4
+ var dividerLabelTextStyle = 'Divider_dividerLabelTextStyle__1desuf1c';
5
+ var dividerRecipe = createRuntimeFn({defaultClassName:'Divider_dividerRecipe__1desuf10',variantClassNames:{orientation:{horizontal:'Divider_dividerRecipe_orientation_horizontal__1desuf11',vertical:'Divider_dividerRecipe_orientation_vertical__1desuf12'},variant:{solid:'Divider_dividerRecipe_variant_solid__1desuf13',dashed:'Divider_dividerRecipe_variant_dashed__1desuf14',dotted:'Divider_dividerRecipe_variant_dotted__1desuf15'}},defaultVariants:{orientation:'horizontal',variant:'solid'},compoundVariants:[[{orientation:'vertical',variant:'dashed'},'Divider_dividerRecipe_compound_0__1desuf16'],[{orientation:'vertical',variant:'dotted'},'Divider_dividerRecipe_compound_1__1desuf17']]});
6
+ var dividerWithLabelRecipe = createRuntimeFn({defaultClassName:'Divider_dividerWithLabelRecipe__1desuf18',variantClassNames:{variant:{solid:'Divider_dividerWithLabelRecipe_variant_solid__1desuf19',dashed:'Divider_dividerWithLabelRecipe_variant_dashed__1desuf1a',dotted:'Divider_dividerWithLabelRecipe_variant_dotted__1desuf1b'}},defaultVariants:{variant:'solid'},compoundVariants:[]});
7
+
8
+ export { dividerLabelTextStyle, dividerRecipe, dividerWithLabelRecipe };
9
+ //# sourceMappingURL=Divider.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Divider.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import React from 'react';
4
+ import { cx } from '../../../utils/cx.js';
5
+ import { dividerLabelTextStyle, dividerWithLabelRecipe, dividerRecipe } from './Divider.css.js';
6
+
7
+ const SPACING_MAP = {
8
+ 0: '0',
9
+ 1: 'var(--etui-spacing-xs)',
10
+ 2: 'var(--etui-spacing-sm)',
11
+ 3: 'var(--etui-spacing-md)',
12
+ 4: 'var(--etui-spacing-lg)',
13
+ 5: 'var(--etui-spacing-xl)',
14
+ 6: 'var(--etui-spacing-xxl)',
15
+ 7: 'var(--etui-spacing-xxxl)',
16
+ };
17
+ function resolveSpacing(spacing) {
18
+ if (spacing === undefined)
19
+ return '0';
20
+ if (typeof spacing === 'number')
21
+ return SPACING_MAP[spacing] ?? '0';
22
+ return spacing;
23
+ }
24
+ /**
25
+ * Thin horizontal or vertical rule, optionally with an inline label.
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * <Stack>
30
+ * <SectionA />
31
+ * <Divider spacing={3} />
32
+ * <SectionB />
33
+ * </Stack>
34
+ *
35
+ * <Divider label="Advanced" />
36
+ * ```
37
+ */
38
+ const Divider = /*#__PURE__*/ React.memo(({ orientation = 'horizontal', variant = 'solid', spacing = 0, label, className, style, testId, ref, ...rest }) => {
39
+ const spacingValue = resolveSpacing(spacing);
40
+ const marginStyle = orientation === 'horizontal'
41
+ ? { marginTop: spacingValue, marginBottom: spacingValue }
42
+ : { marginLeft: spacingValue, marginRight: spacingValue };
43
+ if (label && orientation === 'horizontal') {
44
+ return (jsx("div", { ref: ref, role: "separator", "aria-orientation": "horizontal", className: cx(dividerWithLabelRecipe({ variant }), className), style: { ...marginStyle, ...style }, "data-testid": testId, ...rest, children: jsx("span", { className: dividerLabelTextStyle, children: label }) }));
45
+ }
46
+ return (jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, className: cx(dividerRecipe({ orientation, variant }), className), style: { ...marginStyle, ...style }, "data-testid": testId, ...rest }));
47
+ });
48
+ Divider.displayName = 'Divider';
49
+
50
+ export { Divider };
51
+ //# sourceMappingURL=Divider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Divider.js","sources":["../../../../../../src/components/layout/Divider/Divider.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAWA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGF;;AAC6B;;AACM;AACjC;AACF;AAEA;;;;;;;;;;;;;AAaG;AACI;AAYH;AACA;;;AAKA;;;AAgBA;AAWF;AAGF;;"}
@@ -0,0 +1,10 @@
1
+ import './../../../assets/src/components/layout/ListItem/ListItem.css.ts.vanilla-BwAZrX2f.css';
2
+ import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
+
4
+ var listItemContentStyle = 'ListItem_listItemContentStyle__9m667ic';
5
+ var listItemLeadingStyle = 'ListItem_listItemLeadingStyle__9m667ib';
6
+ var listItemRecipe = createRuntimeFn({defaultClassName:'ListItem_listItemRecipe__9m667i0',variantClassNames:{density:{compact:'ListItem_listItemRecipe_density_compact__9m667i1',comfortable:'ListItem_listItemRecipe_density_comfortable__9m667i2'},clickable:{true:'ListItem_listItemRecipe_clickable_true__9m667i3',false:'ListItem_listItemRecipe_clickable_false__9m667i4'},selected:{true:'ListItem_listItemRecipe_selected_true__9m667i5',false:'ListItem_listItemRecipe_selected_false__9m667i6'},active:{true:'ListItem_listItemRecipe_active_true__9m667i7',false:'ListItem_listItemRecipe_active_false__9m667i8'},disabled:{true:'ListItem_listItemRecipe_disabled_true__9m667i9',false:'ListItem_listItemRecipe_disabled_false__9m667ia'}},defaultVariants:{density:'comfortable',clickable:false,selected:false,active:false,disabled:false},compoundVariants:[]});
7
+ var listItemTrailingStyle = 'ListItem_listItemTrailingStyle__9m667id';
8
+
9
+ export { listItemContentStyle, listItemLeadingStyle, listItemRecipe, listItemTrailingStyle };
10
+ //# sourceMappingURL=ListItem.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListItem.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import React, { useCallback } from 'react';
4
+ import { cx } from '../../../utils/cx.js';
5
+ import { listItemLeadingStyle, listItemContentStyle, listItemTrailingStyle, listItemRecipe } from './ListItem.css.js';
6
+
7
+ /**
8
+ * Reusable list row with leading / trailing slots and hover/selected/active
9
+ * states. Becomes keyboard-activatable when `onClick` is provided (Enter
10
+ * and Space trigger the handler).
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ListItem
15
+ * leading={<FileIcon />}
16
+ * trailing={<Badge color="success">done</Badge>}
17
+ * selected={id === activeId}
18
+ * onClick={() => select(id)}
19
+ * >
20
+ * scene.blend
21
+ * </ListItem>
22
+ * ```
23
+ */
24
+ const ListItem = /*#__PURE__*/ React.memo(({ onClick, leading, trailing, selected = false, active = false, disabled = false, density = 'comfortable', children, className, style, testId, ref, ...rest }) => {
25
+ const clickable = !!onClick && !disabled;
26
+ const handleKeyDown = useCallback((event) => {
27
+ if (!clickable)
28
+ return;
29
+ if (event.key === 'Enter' || event.key === ' ') {
30
+ event.preventDefault();
31
+ onClick?.(event);
32
+ }
33
+ }, [clickable, onClick]);
34
+ return (jsxs("div", { ref: ref, role: clickable ? 'button' : undefined, tabIndex: clickable ? 0 : undefined, "aria-disabled": disabled || undefined, "data-disabled": disabled ? 'true' : 'false', "data-selected": selected ? 'true' : undefined, "data-active": active ? 'true' : undefined, onClick: clickable ? onClick : undefined, onKeyDown: handleKeyDown, className: cx(listItemRecipe({
35
+ density,
36
+ clickable: clickable || undefined,
37
+ selected: selected || undefined,
38
+ active: active || undefined,
39
+ disabled: disabled || undefined,
40
+ }), className), style: style, "data-testid": testId, ...rest, children: [leading && jsx("span", { className: listItemLeadingStyle, children: leading }), jsx("span", { className: listItemContentStyle, children: children }), trailing && jsx("span", { className: listItemTrailingStyle, children: trailing })] }));
41
+ });
42
+ ListItem.displayName = 'ListItem';
43
+
44
+ export { ListItem };
45
+ //# sourceMappingURL=ListItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListItem.js","sources":["../../../../../../src/components/layout/ListItem/ListItem.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAYA;;;;;;;;;;;;;;;;AAgBG;;;AAmBC;AAEI;;AACA;;AAEE;;AAIJ;AAIF;;;;;;AAkBO;AAYT;AAGF;;"}
@@ -0,0 +1,13 @@
1
+ import './../../../assets/src/components/layout/PageHeader/PageHeader.css.ts.vanilla-DdbyyWAN.css';
2
+ import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
+
4
+ var pageHeaderActionsStyle = 'PageHeader_pageHeaderActionsStyle__1uiranpe';
5
+ var pageHeaderBreadcrumbsStyle = 'PageHeader_pageHeaderBreadcrumbsStyle__1uiranpd';
6
+ var pageHeaderIconStyle = 'PageHeader_pageHeaderIconStyle__1uiranp6';
7
+ var pageHeaderRecipe = createRuntimeFn({defaultClassName:'PageHeader_pageHeaderRecipe__1uiranp0',variantClassNames:{size:{sm:'PageHeader_pageHeaderRecipe_size_sm__1uiranp1',md:'PageHeader_pageHeaderRecipe_size_md__1uiranp2',lg:'PageHeader_pageHeaderRecipe_size_lg__1uiranp3'},bordered:{true:'PageHeader_pageHeaderRecipe_bordered_true__1uiranp4',false:'PageHeader_pageHeaderRecipe_bordered_false__1uiranp5'}},defaultVariants:{size:'md',bordered:true},compoundVariants:[]});
8
+ var pageHeaderSubtitleStyle = 'PageHeader_pageHeaderSubtitleStyle__1uiranpc';
9
+ var pageHeaderTitleColumnStyle = 'PageHeader_pageHeaderTitleColumnStyle__1uiranp7';
10
+ var pageHeaderTitleRecipe = createRuntimeFn({defaultClassName:'PageHeader_pageHeaderTitleRecipe__1uiranp8',variantClassNames:{size:{sm:'PageHeader_pageHeaderTitleRecipe_size_sm__1uiranp9',md:'PageHeader_pageHeaderTitleRecipe_size_md__1uiranpa',lg:'PageHeader_pageHeaderTitleRecipe_size_lg__1uiranpb'}},defaultVariants:{size:'md'},compoundVariants:[]});
11
+
12
+ export { pageHeaderActionsStyle, pageHeaderBreadcrumbsStyle, pageHeaderIconStyle, pageHeaderRecipe, pageHeaderSubtitleStyle, pageHeaderTitleColumnStyle, pageHeaderTitleRecipe };
13
+ //# sourceMappingURL=PageHeader.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageHeader.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import React from 'react';
4
+ import { cx } from '../../../utils/cx.js';
5
+ import { pageHeaderIconStyle, pageHeaderTitleColumnStyle, pageHeaderBreadcrumbsStyle, pageHeaderTitleRecipe, pageHeaderSubtitleStyle, pageHeaderActionsStyle, pageHeaderRecipe } from './PageHeader.css.js';
6
+
7
+ /**
8
+ * Structural page/view header with optional breadcrumbs, subtitle,
9
+ * leading icon, and right-aligned actions.
10
+ *
11
+ * Renders a semantic `<header>` element.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <PageHeader
16
+ * icon={<FolderIcon size="lg" />}
17
+ * title="Project Assets"
18
+ * subtitle="124 items"
19
+ * actions={<Button variant="filled">Upload</Button>}
20
+ * />
21
+ * ```
22
+ */
23
+ const PageHeader = /*#__PURE__*/ React.memo(({ icon, title, subtitle, actions, breadcrumbs, size = 'md', bordered = true, className, style, testId, ref, ...rest }) => {
24
+ return (jsxs("header", { ref: ref, className: cx(pageHeaderRecipe({ size, bordered }), className), style: style, "data-testid": testId, ...rest, children: [icon && jsx("span", { className: pageHeaderIconStyle, children: icon }), jsxs("div", { className: pageHeaderTitleColumnStyle, children: [breadcrumbs && (jsx("div", { className: pageHeaderBreadcrumbsStyle, children: breadcrumbs })), jsx("h1", { className: pageHeaderTitleRecipe({ size }), children: title }), subtitle && (jsx("div", { className: pageHeaderSubtitleStyle, children: subtitle }))] }), actions && jsx("div", { className: pageHeaderActionsStyle, children: actions })] }));
25
+ });
26
+ PageHeader.displayName = 'PageHeader';
27
+
28
+ export { PageHeader };
29
+ //# sourceMappingURL=PageHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageHeader.js","sources":["../../../../../../src/components/layout/PageHeader/PageHeader.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAeA;;;;;;;;;;;;;;;AAeG;AACI;;AAsCL;AAGF;;"}
@@ -1,4 +1,4 @@
1
- import './../../../assets/src/components/layout/SplitPane/SplitPane.css.ts.vanilla-BFxdvwyI.css';
1
+ import './../../../assets/src/components/layout/SplitPane/SplitPane.css.ts.vanilla-BGFZ7zDa.css';
2
2
  import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
3
 
4
4
  var containerRecipe = createRuntimeFn({defaultClassName:'SplitPane_containerRecipe__13xgg0i0',variantClassNames:{direction:{horizontal:'SplitPane_containerRecipe_direction_horizontal__13xgg0i1',vertical:'SplitPane_containerRecipe_direction_vertical__13xgg0i2'}},defaultVariants:{},compoundVariants:[]});
@@ -5,12 +5,15 @@ import { cx } from '../../../utils/cx.js';
5
5
  import { tabPanelStyle } from './Tabs.css.js';
6
6
 
7
7
  // --- Component ---
8
- const TabPanel = ({ value, children, keepMounted = false, className, style, testId, ref, ...rest }) => {
9
- const { activeValue, tabsId } = useTabsContext();
8
+ const TabPanel = ({ value, children, keepMounted, className, style, testId, ref, ...rest }) => {
9
+ const ctx = useTabsContext();
10
+ const { activeValue, tabsId } = ctx;
10
11
  const isActive = activeValue === value;
12
+ // Explicit child prop wins over the parent cascade. Undefined = inherit.
13
+ const effectiveKeepMounted = keepMounted ?? ctx.keepMounted;
11
14
  const tabId = `tabs-${tabsId}-tab-${value}`;
12
15
  const panelId = `tabs-${tabsId}-panel-${value}`;
13
- if (!isActive && !keepMounted) {
16
+ if (!isActive && !effectiveKeepMounted) {
14
17
  return null;
15
18
  }
16
19
  return (jsx("div", { ref: ref, role: "tabpanel", id: panelId, "aria-labelledby": tabId, tabIndex: isActive ? 0 : -1, hidden: !isActive || undefined, className: cx(tabPanelStyle, className), style: {
@@ -1 +1 @@
1
- {"version":3,"file":"TabPanel.js","sources":["../../../../../../src/components/navigation/Tabs/TabPanel.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAQA;AAEO;;AAWL;AAEA;AACA;AAEA;AACE;;;AAaI;AACA;AACD;AAOP;AAEA;;"}
1
+ {"version":3,"file":"TabPanel.js","sources":["../../../../../../src/components/navigation/Tabs/TabPanel.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAQA;AAEO;AAUL;AACA;AACA;;AAGA;AAEA;AACA;AAEA;AACE;;;AAaI;AACA;AACD;AAOP;AAEA;;"}
@@ -31,7 +31,7 @@ function useTabsContext() {
31
31
  * </Tabs>
32
32
  * ```
33
33
  */
34
- const Tabs = ({ value: valueProp, defaultValue, variant = 'underline', size = 'md', orientation = 'horizontal', fullWidth = false, pillsFrame = true, children, onChange, className, style, testId, ref, ...rest }) => {
34
+ const Tabs = ({ value: valueProp, defaultValue, variant = 'underline', size = 'md', orientation = 'horizontal', fullWidth = false, pillsFrame = true, keepMounted = false, children, onChange, className, style, testId, ref, ...rest }) => {
35
35
  const autoId = useId();
36
36
  const tabsId = autoId;
37
37
  const [internalValue, setInternalValue] = useState(defaultValue ?? '');
@@ -51,6 +51,7 @@ const Tabs = ({ value: valueProp, defaultValue, variant = 'underline', size = 'm
51
51
  orientation,
52
52
  fullWidth,
53
53
  pillsFrame,
54
+ keepMounted,
54
55
  tabsId,
55
56
  }), [
56
57
  activeValue,
@@ -60,6 +61,7 @@ const Tabs = ({ value: valueProp, defaultValue, variant = 'underline', size = 'm
60
61
  orientation,
61
62
  fullWidth,
62
63
  pillsFrame,
64
+ keepMounted,
63
65
  tabsId,
64
66
  ]);
65
67
  return (jsx(TabsContext.Provider, { value: contextValue, children: jsx("div", { ref: ref, className: cx(tabsRootRecipe({ orientation }), className), style: style, "data-testid": testId, ...rest, children: children }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.js","sources":["../../../../../../src/components/navigation/Tabs/Tabs.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAcA;AAEA;;AAGE;;AAEE;;AAEF;AACF;AAEA;AAEA;;;;;;;;;;;;;;;;AAgBG;;AAiBD;;AAGA;AACA;;AAGA;;;;AAKI;AACF;AAIF;;;;;;;;;AAUG;;;;;;;;;AAUA;AAGH;AAaF;AAEA;;"}
1
+ {"version":3,"file":"Tabs.js","sources":["../../../../../../src/components/navigation/Tabs/Tabs.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAcA;AAEA;;AAGE;;AAEE;;AAEF;AACF;AAEA;AAEA;;;;;;;;;;;;;;;;AAgBG;AACI;AAiBL;;AAGA;AACA;;AAGA;;;;AAKI;AACF;AAIF;;;;;;;;;;AAWG;;;;;;;;;;AAWA;AAGH;AAaF;AAEA;;"}