@mastra/playground-ui 51.2.0 → 51.3.0-alpha.1

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 (160) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE.md +6 -4
  3. package/dist/components/DataCodeSection.cjs.js +1 -1
  4. package/dist/components/DataCodeSection.es.js +1 -1
  5. package/dist/components/DataPanel.cjs.js +1 -1
  6. package/dist/components/DataPanel.es.js +1 -1
  7. package/dist/components/FormFieldBlocks.cjs.js +1 -1
  8. package/dist/components/FormFieldBlocks.es.js +1 -1
  9. package/dist/components/ListSearch.cjs.js +13 -2
  10. package/dist/components/ListSearch.cjs.js.map +1 -1
  11. package/dist/components/ListSearch.es.js +14 -3
  12. package/dist/components/ListSearch.es.js.map +1 -1
  13. package/dist/components/LogsDataList.cjs.js +0 -1
  14. package/dist/components/LogsDataList.cjs.js.map +1 -1
  15. package/dist/components/LogsDataList.es.js +0 -1
  16. package/dist/components/LogsDataList.es.js.map +1 -1
  17. package/dist/components/MarkdownRenderer.cjs.js +3 -65
  18. package/dist/components/MarkdownRenderer.cjs.js.map +1 -1
  19. package/dist/components/MarkdownRenderer.es.js +1 -67
  20. package/dist/components/MarkdownRenderer.es.js.map +1 -1
  21. package/dist/components/ai/message-reveal.cjs.js +50 -0
  22. package/dist/components/ai/message-reveal.cjs.js.map +1 -0
  23. package/dist/components/ai/message-reveal.d.ts +2 -0
  24. package/dist/components/ai/message-reveal.es.js +44 -0
  25. package/dist/components/ai/message-reveal.es.js.map +1 -0
  26. package/dist/{data-code-section-sK4cZuA-.cjs → data-code-section-C3ZRkULz.cjs} +2 -2
  27. package/dist/{data-code-section-sK4cZuA-.cjs.map → data-code-section-C3ZRkULz.cjs.map} +1 -1
  28. package/dist/{data-code-section-g1jBtzwR.js → data-code-section-CSt_ZuUP.js} +2 -2
  29. package/dist/{data-code-section-g1jBtzwR.js.map → data-code-section-CSt_ZuUP.js.map} +1 -1
  30. package/dist/{data-panel-B3AECYLW.cjs → data-panel-DHNc5Y4L.cjs} +2 -2
  31. package/dist/{data-panel-B3AECYLW.cjs.map → data-panel-DHNc5Y4L.cjs.map} +1 -1
  32. package/dist/{data-panel-B527Q_Zh.js → data-panel-DJpAfEsG.js} +2 -2
  33. package/dist/{data-panel-B527Q_Zh.js.map → data-panel-DJpAfEsG.js.map} +1 -1
  34. package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
  35. package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
  36. package/dist/domains/traces/components/timeline-name-col.cjs.js +1 -1
  37. package/dist/domains/traces/components/timeline-name-col.cjs.js.map +1 -1
  38. package/dist/domains/traces/components/timeline-name-col.es.js +1 -1
  39. package/dist/domains/traces/components/timeline-name-col.es.js.map +1 -1
  40. package/dist/domains/traces/components/trace-data-panel-view.cjs.js +44 -9
  41. package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
  42. package/dist/domains/traces/components/trace-data-panel-view.es.js +45 -10
  43. package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
  44. package/dist/domains/traces/components/trace-timeline.cjs.js +18 -14
  45. package/dist/domains/traces/components/trace-timeline.cjs.js.map +1 -1
  46. package/dist/domains/traces/components/trace-timeline.es.js +18 -14
  47. package/dist/domains/traces/components/trace-timeline.es.js.map +1 -1
  48. package/dist/domains/traces/hooks/use-branch.cjs.js +4 -0
  49. package/dist/domains/traces/hooks/use-branch.cjs.js.map +1 -1
  50. package/dist/domains/traces/hooks/use-branch.es.js +4 -0
  51. package/dist/domains/traces/hooks/use-branch.es.js.map +1 -1
  52. package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js +4 -0
  53. package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js.map +1 -1
  54. package/dist/domains/traces/hooks/use-trace-light-spans.es.js +4 -0
  55. package/dist/domains/traces/hooks/use-trace-light-spans.es.js.map +1 -1
  56. package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js +2 -2
  57. package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js.map +1 -1
  58. package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js +2 -2
  59. package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js.map +1 -1
  60. package/dist/domains/traces/hooks/use-trace-search.cjs.js +21 -0
  61. package/dist/domains/traces/hooks/use-trace-search.cjs.js.map +1 -0
  62. package/dist/domains/traces/hooks/use-trace-search.d.ts +2 -0
  63. package/dist/domains/traces/hooks/use-trace-search.es.js +17 -0
  64. package/dist/domains/traces/hooks/use-trace-search.es.js.map +1 -0
  65. package/dist/domains/traces/hooks/use-trace-spans.cjs.js +11 -1
  66. package/dist/domains/traces/hooks/use-trace-spans.cjs.js.map +1 -1
  67. package/dist/domains/traces/hooks/use-trace-spans.es.js +11 -1
  68. package/dist/domains/traces/hooks/use-trace-spans.es.js.map +1 -1
  69. package/dist/domains/traces/hooks.cjs.js +2 -0
  70. package/dist/domains/traces/hooks.cjs.js.map +1 -1
  71. package/dist/domains/traces/hooks.es.js +1 -0
  72. package/dist/domains/traces/hooks.es.js.map +1 -1
  73. package/dist/domains/traces/types.cjs.js.map +1 -1
  74. package/dist/domains/traces/types.es.js.map +1 -1
  75. package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js +47 -0
  76. package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js.map +1 -0
  77. package/dist/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +2 -0
  78. package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js +43 -0
  79. package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js.map +1 -0
  80. package/dist/domains/traces/utils/flatten-to-search-text.cjs.js +78 -0
  81. package/dist/domains/traces/utils/flatten-to-search-text.cjs.js.map +1 -0
  82. package/dist/domains/traces/utils/flatten-to-search-text.d.ts +2 -0
  83. package/dist/domains/traces/utils/flatten-to-search-text.es.js +74 -0
  84. package/dist/domains/traces/utils/flatten-to-search-text.es.js.map +1 -0
  85. package/dist/domains/traces/utils/to-searchable-spans.cjs.js +22 -0
  86. package/dist/domains/traces/utils/to-searchable-spans.cjs.js.map +1 -0
  87. package/dist/domains/traces/utils/to-searchable-spans.d.ts +2 -0
  88. package/dist/domains/traces/utils/to-searchable-spans.es.js +17 -0
  89. package/dist/domains/traces/utils/to-searchable-spans.es.js.map +1 -0
  90. package/dist/domains/traces/utils.cjs.js +7 -0
  91. package/dist/domains/traces/utils.cjs.js.map +1 -1
  92. package/dist/domains/traces/utils.es.js +3 -0
  93. package/dist/domains/traces/utils.es.js.map +1 -1
  94. package/dist/domains/traces.cjs.js +9 -0
  95. package/dist/domains/traces.cjs.js.map +1 -1
  96. package/dist/domains/traces.es.js +4 -0
  97. package/dist/domains/traces.es.js.map +1 -1
  98. package/dist/ee/topics/components/topic-trace-details-panel.cjs.js +2 -2
  99. package/dist/ee/topics/components/topic-trace-details-panel.cjs.js.map +1 -1
  100. package/dist/ee/topics/components/topic-trace-details-panel.es.js +2 -2
  101. package/dist/ee/topics/components/topic-trace-details-panel.es.js.map +1 -1
  102. package/dist/hooks/use-text-highlight.cjs.js +68 -0
  103. package/dist/hooks/use-text-highlight.cjs.js.map +1 -0
  104. package/dist/hooks/use-text-highlight.d.ts +2 -0
  105. package/dist/hooks/use-text-highlight.es.js +64 -0
  106. package/dist/hooks/use-text-highlight.es.js.map +1 -0
  107. package/dist/{search-field-block-BqRM53jf.cjs → search-field-block-CjCIzUhN.cjs} +8 -3
  108. package/dist/search-field-block-CjCIzUhN.cjs.map +1 -0
  109. package/dist/{search-field-block-CgrC6f9t.js → search-field-block-DoNywsJC.js} +8 -3
  110. package/dist/search-field-block-DoNywsJC.js.map +1 -0
  111. package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +2 -2
  112. package/dist/src/domains/traces/components/trace-timeline.d.ts +4 -2
  113. package/dist/src/domains/traces/hooks/index.d.ts +1 -0
  114. package/dist/src/domains/traces/hooks/use-branch.d.ts +2 -2
  115. package/dist/src/domains/traces/hooks/use-trace-light-spans.d.ts +2 -2
  116. package/dist/src/domains/traces/hooks/use-trace-or-branch-spans.d.ts +5 -2
  117. package/dist/src/domains/traces/hooks/use-trace-search.d.ts +27 -0
  118. package/dist/src/domains/traces/hooks/use-trace-spans.d.ts +11 -2
  119. package/dist/src/domains/traces/types.d.ts +16 -0
  120. package/dist/src/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +19 -0
  121. package/dist/src/domains/traces/utils/flatten-to-search-text.d.ts +25 -0
  122. package/dist/src/domains/traces/utils/index.d.ts +3 -0
  123. package/dist/src/domains/traces/utils/to-searchable-spans.d.ts +41 -0
  124. package/dist/src/ds/components/Arrival/arrival.stories.d.ts +6 -0
  125. package/dist/src/ds/components/Card/card.stories.d.ts +8 -0
  126. package/dist/src/ds/components/Columns/columns.stories.d.ts +7 -0
  127. package/dist/src/ds/components/DataDetailsPanel/data-details-panel.stories.d.ts +9 -0
  128. package/dist/src/ds/components/DataFilter/select-data-filter.stories.d.ts +8 -0
  129. package/dist/src/ds/components/DateRangeTimeline/date-range-timeline.stories.d.ts +8 -0
  130. package/dist/src/ds/components/ErrorState/error-state.stories.d.ts +7 -0
  131. package/dist/src/ds/components/FormFieldBlocks/fields/search-field-block.d.ts +4 -1
  132. package/dist/src/ds/components/ListSearch/list-search.d.ts +6 -1
  133. package/dist/src/ds/components/ListSearch/list-search.stories.d.ts +7 -0
  134. package/dist/src/ds/components/LogsDataList/logs-data-list.stories.d.ts +8 -0
  135. package/dist/src/ds/components/MessageScroller/message-scroller.stories.d.ts +7 -0
  136. package/dist/src/ds/components/MetricsLineChart/metrics-line-chart.stories.d.ts +8 -0
  137. package/dist/src/ds/components/PageHeader/page-header.stories.d.ts +8 -0
  138. package/dist/src/ds/components/PageLayout/page-layout.stories.d.ts +8 -0
  139. package/dist/src/ds/components/PendingIndicator/pending-indicator.stories.d.ts +7 -0
  140. package/dist/src/ds/components/PermissionDenied/permission-denied.stories.d.ts +8 -0
  141. package/dist/src/ds/components/PrevNextNav/prev-next-nav.stories.d.ts +8 -0
  142. package/dist/src/ds/components/SessionExpired/session-expired.stories.d.ts +7 -0
  143. package/dist/src/ds/components/Shimmer/shimmer.stories.d.ts +7 -0
  144. package/dist/src/ds/components/StatusBadge/status-badge.stories.d.ts +8 -0
  145. package/dist/src/ds/components/ThreadList/thread-list.stories.d.ts +8 -0
  146. package/dist/src/ds/components/ThreadRail/thread-rail.stories.d.ts +7 -0
  147. package/dist/src/ds/components/TokenBudget/token-budget.stories.d.ts +8 -0
  148. package/dist/src/ds/components/ai/message-reveal/index.d.ts +1 -0
  149. package/dist/src/ds/components/ai/message-reveal/message-reveal.d.ts +22 -0
  150. package/dist/src/hooks/use-text-highlight.d.ts +18 -0
  151. package/dist/src/test/highlight-api.d.ts +28 -0
  152. package/dist/style.css +80 -0
  153. package/dist/use-reveal-Sa456jZb.cjs +70 -0
  154. package/dist/use-reveal-Sa456jZb.cjs.map +1 -0
  155. package/dist/use-reveal-d77hxHz9.js +68 -0
  156. package/dist/use-reveal-d77hxHz9.js.map +1 -0
  157. package/dist/use-text-highlight.css +8 -0
  158. package/package.json +8 -8
  159. package/dist/search-field-block-BqRM53jf.cjs.map +0 -1
  160. package/dist/search-field-block-CgrC6f9t.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @mastra/playground-ui
2
2
 
3
+ ## 51.3.0-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Search the spans of a trace from the timeline in Studio ([#22456](https://github.com/mastra-ai/mastra/pull/22456))
8
+
9
+ A long trace made you scroll to find the one span you cared about. The trace timeline now has a search field, sitting on the left of the span type legend. Type in it and the timeline narrows to the matching spans.
10
+
11
+ Matching runs over the whole span payload, not a fixed list of fields, so a span is reachable by anything it carries: a tool argument, a model name, an error message, or a value nested deep in its metadata. Field names are searchable too, so you can look for the shape of a payload and not only its content. Matching is case-insensitive, and the work of flattening each span happens once when the trace loads rather than on every keystroke.
12
+
13
+ A matching span is never shown out of context. Its full parent chain stays visible so you can see where it sits in the trace, and its own subtree stays visible too, so searching for a tool call still shows you what that tool call did. The field keeps working whatever order the spans arrive in, a query that matches nothing leaves the field in place so you can undo it, and clearing the field restores the whole trace.
14
+
15
+ - Add a Cmd+Shift+F (Ctrl+Shift+F on Windows/Linux) shortcut to `ListSearch` that focuses and selects the search field, so every Studio list page (agents, tools, workflows, MCP servers, processors, schedules, datasets, experiments, ...) can be filtered without reaching for the mouse. Pass `shortcutDisabled` on a secondary `ListSearch` if a page renders two at once. ([#22461](https://github.com/mastra-ai/mastra/pull/22461))
16
+
17
+ - Load the full trace when a trace is opened in Studio. The trace list keeps using the lightweight ([#22475](https://github.com/mastra-ai/mastra/pull/22475))
18
+ projection, but the trace detail panel, the logs page featured trace and the topics trace panel now
19
+ read `getTrace`, so span input, output, attributes, tags and links are available to the timeline,
20
+ the span panel and trace search instead of being silently missing.
21
+
22
+ - Search terms typed into the trace search field are now highlighted where the matches actually are: on the span names in the timeline tree, and throughout the span side panel, so a match is easy to spot inside a large payload. ([#22475](https://github.com/mastra-ai/mastra/pull/22475))
23
+
24
+ Regions opt in to highlighting rather than opting out, so the chrome around a trace — the panel header, the trace metadata, the tab labels, the span type legend — is never painted, and nothing added later has to remember to exclude itself. Highlighting starts from the second character: a single letter matches almost everywhere and paints noise rather than results.
25
+
26
+ It uses the CSS Custom Highlight API, so no wrapper element is injected: the text stays exactly as rendered, and selection and copy/paste are unaffected. Browsers without the API simply show no highlight.
27
+
28
+ - Updated dependencies [[`295e506`](https://github.com/mastra-ai/mastra/commit/295e506b9e6cec99e7181c5f712648888cd9486f), [`8c3be07`](https://github.com/mastra-ai/mastra/commit/8c3be0761a862c5c035ed6e5d633de87cbba20e7), [`078affd`](https://github.com/mastra-ai/mastra/commit/078affdaea57ac5e95a77e9e7b197d1878190684), [`9e3403e`](https://github.com/mastra-ai/mastra/commit/9e3403e9868240cb18841898e84cf008ebd7a87e), [`791bf5e`](https://github.com/mastra-ai/mastra/commit/791bf5e81cd27e2e1cff66122f1380ab8a3dda41)]:
29
+ - @mastra/memory@1.28.1-alpha.0
30
+ - @mastra/core@1.63.1-alpha.1
31
+ - @mastra/client-js@1.42.3-alpha.1
32
+ - @mastra/react@1.4.8-alpha.1
33
+
34
+ ## 51.3.0-alpha.0
35
+
36
+ ### Minor Changes
37
+
38
+ - Added `@mastra/playground-ui/components/ai/message-reveal`, which paces a whole assistant message — prose, reasoning, tool rows, cards — on one clock, so its parts arrive in the order the model wrote them. ([#22408](https://github.com/mastra-ai/mastra/pull/22408))
39
+
40
+ Before, a renderer paced its own text with `useRevealedText`, which could only slow prose down: everything written between two passages landed at once, so a tool row appeared while the sentence before it was still being typed out.
41
+
42
+ ```tsx
43
+ import { useRevealedParts } from '@mastra/playground-ui/components/ai/message-reveal';
44
+
45
+ const parts = useRevealedParts(message.content.parts, streaming);
46
+
47
+ <MessageFactory message={{ ...message, content: { ...message.content, parts } }} {...renderers} />;
48
+ ```
49
+
50
+ The projection happens above the renderers, so none of them has to know a reveal is running.
51
+
52
+ ### Patch Changes
53
+
54
+ - Added Storybook examples for every published Playground UI component that did not already have coverage. ([#22422](https://github.com/mastra-ai/mastra/pull/22422))
55
+
56
+ - Updated dependencies [[`bae1502`](https://github.com/mastra-ai/mastra/commit/bae150254b06a4da6964d7c137af97f336362359)]:
57
+ - @mastra/core@1.63.1-alpha.0
58
+ - @mastra/client-js@1.42.3-alpha.0
59
+ - @mastra/react@1.4.8-alpha.0
60
+
3
61
  ## 51.2.0
4
62
 
5
63
  ### Minor Changes
package/LICENSE.md CHANGED
@@ -1,10 +1,12 @@
1
1
  Portions of this software are licensed as follows:
2
2
 
3
- - All content that resides under any directory named "ee/" within this
3
+ - All content that resides under any directory named `ee/` within this
4
4
  repository, including but not limited to:
5
- - `packages/core/src/auth/ee/`
6
- - `packages/server/src/server/auth/ee/`
7
- is licensed under the license defined in `ee/LICENSE`.
5
+ - `@mastra/core/auth/ee`
6
+ - `@mastra/core/agent-builder/ee`
7
+ - `@mastra/editor/ee`
8
+
9
+ is licensed under the license defined in [`ee/LICENSE`](https://github.com/mastra-ai/mastra/blob/main/ee/LICENSE).
8
10
 
9
11
  - All third-party components incorporated into the Mastra Software are
10
12
  licensed under the original license provided by the owner of the
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const dataCodeSection = require('../data-code-section-sK4cZuA-.cjs');
5
+ const dataCodeSection = require('../data-code-section-C3ZRkULz.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,2 +1,2 @@
1
- export { D as DataCodeSection } from '../data-code-section-g1jBtzwR.js';
1
+ export { D as DataCodeSection } from '../data-code-section-CSt_ZuUP.js';
2
2
  //# sourceMappingURL=DataCodeSection.es.js.map
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const dataPanel = require('../data-panel-B3AECYLW.cjs');
5
+ const dataPanel = require('../data-panel-DHNc5Y4L.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,2 +1,2 @@
1
- export { D as DataPanel } from '../data-panel-B527Q_Zh.js';
1
+ export { D as DataPanel } from '../data-panel-DJpAfEsG.js';
2
2
  //# sourceMappingURL=DataPanel.es.js.map
@@ -6,7 +6,7 @@ const fieldBlock = require('../field-block-BcTR08I7.cjs');
6
6
  const jsxRuntime = require('react/jsx-runtime');
7
7
  const utils_cn = require('../cn-vA5sWo9W.cjs');
8
8
  const textFieldBlock = require('../text-field-block-B4CvIwKh.cjs');
9
- const searchFieldBlock = require('../search-field-block-BqRM53jf.cjs');
9
+ const searchFieldBlock = require('../search-field-block-CjCIzUhN.cjs');
10
10
  const selectFieldBlock = require('../select-field-block-BXjwaMqJ.cjs');
11
11
 
12
12
  function FieldBlocksLayoutColumn({ children, className }) {
@@ -2,7 +2,7 @@ export { F as FieldBlock } from '../field-block-B63CpA4d.js';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { c as cn } from '../cn-BakJzhuv.js';
4
4
  export { T as TextFieldBlock } from '../text-field-block-Ddl2tJ6D.js';
5
- export { S as SearchFieldBlock } from '../search-field-block-CgrC6f9t.js';
5
+ export { S as SearchFieldBlock } from '../search-field-block-DoNywsJC.js';
6
6
  export { S as SelectFieldBlock } from '../select-field-block-CDklwBFe.js';
7
7
 
8
8
  function FieldBlocksLayoutColumn({ children, className }) {
@@ -5,7 +5,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
6
  const React = require('react');
7
7
  const useDebounce = require('use-debounce');
8
- const searchFieldBlock = require('../search-field-block-BqRM53jf.cjs');
8
+ const searchFieldBlock = require('../search-field-block-CjCIzUhN.cjs');
9
+ const keyboard_useKeydown = require('../keyboard/use-keydown.cjs.js');
9
10
 
10
11
  const ListSearch = ({
11
12
  onSearch,
@@ -14,10 +15,19 @@ const ListSearch = ({
14
15
  debounceMs = 300,
15
16
  size,
16
17
  value: controlledValue,
17
- variant = "outline"
18
+ variant = "outline",
19
+ shortcutDisabled = false
18
20
  }) => {
19
21
  const id = React.useId();
20
22
  const [internalValue, setInternalValue] = React.useState(controlledValue ?? "");
23
+ const inputRef = React.useRef(null);
24
+ keyboard_useKeydown.useKeydown({
25
+ "mod+shift+f": () => {
26
+ if (shortcutDisabled) return;
27
+ inputRef.current?.focus();
28
+ inputRef.current?.select();
29
+ }
30
+ });
21
31
  const debouncedSearch = useDebounce.useDebouncedCallback((val) => {
22
32
  onSearch(val);
23
33
  }, debounceMs);
@@ -52,6 +62,7 @@ const ListSearch = ({
52
62
  onReset: handleReset,
53
63
  size,
54
64
  variant,
65
+ inputRef,
55
66
  className: "w-full max-w-120"
56
67
  }
57
68
  );
@@ -1 +1 @@
1
- {"version":3,"file":"ListSearch.cjs.js","sources":["../../src/ds/components/ListSearch/list-search.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useState } from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\nimport { SearchFieldBlock } from '@/ds/components/FormFieldBlocks/fields/search-field-block';\nimport type { InputProps } from '@/ds/components/Input';\n\nexport type ListSearchProps = {\n onSearch: (search: string) => void;\n label: string;\n placeholder: string;\n debounceMs?: number;\n size?: InputProps['size'];\n /**\n * Optional controlled value. When provided, ListSearch stays in sync with this\n * prop — useful when the parent needs to clear the input programmatically\n * (e.g. from a Reset button). If omitted, ListSearch manages its own state.\n */\n value?: string;\n variant?: InputProps['variant'];\n};\n\nexport const ListSearch = ({\n onSearch,\n label,\n placeholder,\n debounceMs = 300,\n size,\n value: controlledValue,\n variant = 'outline',\n}: ListSearchProps) => {\n const id = useId();\n const [internalValue, setInternalValue] = useState(controlledValue ?? '');\n\n const debouncedSearch = useDebouncedCallback((val: string) => {\n onSearch(val);\n }, debounceMs);\n\n // Sync internal state with controlled value (e.g. parent Reset clears it to '').\n // Also cancel any pending debounced callback so a stale handleChange call\n // can't overwrite the newly-applied controlled value.\n useEffect(() => {\n if (controlledValue !== undefined) {\n debouncedSearch.cancel();\n setInternalValue(controlledValue);\n }\n }, [controlledValue, debouncedSearch]);\n\n useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n setInternalValue(e.target.value);\n debouncedSearch(e.target.value);\n },\n [debouncedSearch],\n );\n\n const handleReset = useCallback(() => {\n setInternalValue('');\n onSearch('');\n debouncedSearch.cancel();\n }, [onSearch, debouncedSearch]);\n\n return (\n <SearchFieldBlock\n name={id}\n label={label}\n labelIsHidden\n placeholder={placeholder}\n value={internalValue}\n onChange={handleChange}\n onReset={handleReset}\n size={size}\n variant={variant}\n className=\"w-full max-w-120\"\n />\n );\n};\n"],"names":["useId","useState","useDebouncedCallback","useEffect","useCallback","jsx","SearchFieldBlock"],"mappings":";;;;;;;;;AAoBO,MAAM,aAAa,CAAC;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,GAAA;AAAA,EACb,IAAA;AAAA,EACA,KAAA,EAAO,eAAA;AAAA,EACP,OAAA,GAAU;AACZ,CAAA,KAAuB;AACrB,EAAA,MAAM,KAAKA,WAAA,EAAM;AACjB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIC,cAAA,CAAS,mBAAmB,EAAE,CAAA;AAExE,EAAA,MAAM,eAAA,GAAkBC,gCAAA,CAAqB,CAAC,GAAA,KAAgB;AAC5D,IAAA,QAAA,CAAS,GAAG,CAAA;AAAA,EACd,GAAG,UAAU,CAAA;AAKb,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,MAAA,eAAA,CAAgB,MAAA,EAAO;AACvB,MAAA,gBAAA,CAAiB,eAAe,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,eAAA,EAAiB,eAAe,CAAC,CAAA;AAErC,EAAAA,eAAA,CAAU,MAAM,MAAM,eAAA,CAAgB,QAAO,EAAG,CAAC,eAAe,CAAC,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAeC,iBAAA;AAAA,IACnB,CAAC,CAAA,KAA2C;AAC1C,MAAA,gBAAA,CAAiB,CAAA,CAAE,OAAO,KAAK,CAAA;AAC/B,MAAA,eAAA,CAAgB,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,eAAA,CAAgB,MAAA,EAAO;AAAA,EACzB,CAAA,EAAG,CAAC,QAAA,EAAU,eAAe,CAAC,CAAA;AAE9B,EAAA,uBACEC,cAAA;AAAA,IAACC,iCAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,EAAA;AAAA,MACN,KAAA;AAAA,MACA,aAAA,EAAa,IAAA;AAAA,MACb,WAAA;AAAA,MACA,KAAA,EAAO,aAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MACT,IAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA,EAAU;AAAA;AAAA,GACZ;AAEJ;;;;"}
1
+ {"version":3,"file":"ListSearch.cjs.js","sources":["../../src/ds/components/ListSearch/list-search.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\nimport { SearchFieldBlock } from '@/ds/components/FormFieldBlocks/fields/search-field-block';\nimport type { InputProps } from '@/ds/components/Input';\nimport { useKeydown } from '@/lib/keyboard';\n\nexport type ListSearchProps = {\n onSearch: (search: string) => void;\n label: string;\n placeholder: string;\n debounceMs?: number;\n size?: InputProps['size'];\n /**\n * Optional controlled value. When provided, ListSearch stays in sync with this\n * prop — useful when the parent needs to clear the input programmatically\n * (e.g. from a Reset button). If omitted, ListSearch manages its own state.\n */\n value?: string;\n variant?: InputProps['variant'];\n /**\n * Opts out of the Cmd/Ctrl+Shift+F focus shortcut. Pass this on secondary\n * instances so two search fields on the same page don't fight over focus.\n */\n shortcutDisabled?: boolean;\n};\n\nexport const ListSearch = ({\n onSearch,\n label,\n placeholder,\n debounceMs = 300,\n size,\n value: controlledValue,\n variant = 'outline',\n shortcutDisabled = false,\n}: ListSearchProps) => {\n const id = useId();\n const [internalValue, setInternalValue] = useState(controlledValue ?? '');\n const inputRef = useRef<HTMLInputElement>(null);\n\n useKeydown({\n 'mod+shift+f': () => {\n if (shortcutDisabled) return;\n inputRef.current?.focus();\n inputRef.current?.select();\n },\n });\n\n const debouncedSearch = useDebouncedCallback((val: string) => {\n onSearch(val);\n }, debounceMs);\n\n // Sync internal state with controlled value (e.g. parent Reset clears it to '').\n // Also cancel any pending debounced callback so a stale handleChange call\n // can't overwrite the newly-applied controlled value.\n useEffect(() => {\n if (controlledValue !== undefined) {\n debouncedSearch.cancel();\n setInternalValue(controlledValue);\n }\n }, [controlledValue, debouncedSearch]);\n\n useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n setInternalValue(e.target.value);\n debouncedSearch(e.target.value);\n },\n [debouncedSearch],\n );\n\n const handleReset = useCallback(() => {\n setInternalValue('');\n onSearch('');\n debouncedSearch.cancel();\n }, [onSearch, debouncedSearch]);\n\n return (\n <SearchFieldBlock\n name={id}\n label={label}\n labelIsHidden\n placeholder={placeholder}\n value={internalValue}\n onChange={handleChange}\n onReset={handleReset}\n size={size}\n variant={variant}\n inputRef={inputRef}\n className=\"w-full max-w-120\"\n />\n );\n};\n"],"names":["useId","useState","useRef","useKeydown","useDebouncedCallback","useEffect","useCallback","jsx","SearchFieldBlock"],"mappings":";;;;;;;;;;AA0BO,MAAM,aAAa,CAAC;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,GAAA;AAAA,EACb,IAAA;AAAA,EACA,KAAA,EAAO,eAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,gBAAA,GAAmB;AACrB,CAAA,KAAuB;AACrB,EAAA,MAAM,KAAKA,WAAA,EAAM;AACjB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIC,cAAA,CAAS,mBAAmB,EAAE,CAAA;AACxE,EAAA,MAAM,QAAA,GAAWC,aAAyB,IAAI,CAAA;AAE9C,EAAAC,8BAAA,CAAW;AAAA,IACT,eAAe,MAAM;AACnB,MAAA,IAAI,gBAAA,EAAkB;AACtB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,QAAA,CAAS,SAAS,MAAA,EAAO;AAAA,IAC3B;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAA,GAAkBC,gCAAA,CAAqB,CAAC,GAAA,KAAgB;AAC5D,IAAA,QAAA,CAAS,GAAG,CAAA;AAAA,EACd,GAAG,UAAU,CAAA;AAKb,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,MAAA,eAAA,CAAgB,MAAA,EAAO;AACvB,MAAA,gBAAA,CAAiB,eAAe,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,eAAA,EAAiB,eAAe,CAAC,CAAA;AAErC,EAAAA,eAAA,CAAU,MAAM,MAAM,eAAA,CAAgB,QAAO,EAAG,CAAC,eAAe,CAAC,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAeC,iBAAA;AAAA,IACnB,CAAC,CAAA,KAA2C;AAC1C,MAAA,gBAAA,CAAiB,CAAA,CAAE,OAAO,KAAK,CAAA;AAC/B,MAAA,eAAA,CAAgB,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,eAAA,CAAgB,MAAA,EAAO;AAAA,EACzB,CAAA,EAAG,CAAC,QAAA,EAAU,eAAe,CAAC,CAAA;AAE9B,EAAA,uBACEC,cAAA;AAAA,IAACC,iCAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,EAAA;AAAA,MACN,KAAA;AAAA,MACA,aAAA,EAAa,IAAA;AAAA,MACb,WAAA;AAAA,MACA,KAAA,EAAO,aAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MACT,IAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA,EAAU;AAAA;AAAA,GACZ;AAEJ;;;;"}
@@ -1,7 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { useId, useState, useEffect, useCallback } from 'react';
2
+ import { useId, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { useDebouncedCallback } from 'use-debounce';
4
- import { S as SearchFieldBlock } from '../search-field-block-CgrC6f9t.js';
4
+ import { S as SearchFieldBlock } from '../search-field-block-DoNywsJC.js';
5
+ import { useKeydown } from '../keyboard/use-keydown.es.js';
5
6
 
6
7
  const ListSearch = ({
7
8
  onSearch,
@@ -10,10 +11,19 @@ const ListSearch = ({
10
11
  debounceMs = 300,
11
12
  size,
12
13
  value: controlledValue,
13
- variant = "outline"
14
+ variant = "outline",
15
+ shortcutDisabled = false
14
16
  }) => {
15
17
  const id = useId();
16
18
  const [internalValue, setInternalValue] = useState(controlledValue ?? "");
19
+ const inputRef = useRef(null);
20
+ useKeydown({
21
+ "mod+shift+f": () => {
22
+ if (shortcutDisabled) return;
23
+ inputRef.current?.focus();
24
+ inputRef.current?.select();
25
+ }
26
+ });
17
27
  const debouncedSearch = useDebouncedCallback((val) => {
18
28
  onSearch(val);
19
29
  }, debounceMs);
@@ -48,6 +58,7 @@ const ListSearch = ({
48
58
  onReset: handleReset,
49
59
  size,
50
60
  variant,
61
+ inputRef,
51
62
  className: "w-full max-w-120"
52
63
  }
53
64
  );
@@ -1 +1 @@
1
- {"version":3,"file":"ListSearch.es.js","sources":["../../src/ds/components/ListSearch/list-search.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useState } from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\nimport { SearchFieldBlock } from '@/ds/components/FormFieldBlocks/fields/search-field-block';\nimport type { InputProps } from '@/ds/components/Input';\n\nexport type ListSearchProps = {\n onSearch: (search: string) => void;\n label: string;\n placeholder: string;\n debounceMs?: number;\n size?: InputProps['size'];\n /**\n * Optional controlled value. When provided, ListSearch stays in sync with this\n * prop — useful when the parent needs to clear the input programmatically\n * (e.g. from a Reset button). If omitted, ListSearch manages its own state.\n */\n value?: string;\n variant?: InputProps['variant'];\n};\n\nexport const ListSearch = ({\n onSearch,\n label,\n placeholder,\n debounceMs = 300,\n size,\n value: controlledValue,\n variant = 'outline',\n}: ListSearchProps) => {\n const id = useId();\n const [internalValue, setInternalValue] = useState(controlledValue ?? '');\n\n const debouncedSearch = useDebouncedCallback((val: string) => {\n onSearch(val);\n }, debounceMs);\n\n // Sync internal state with controlled value (e.g. parent Reset clears it to '').\n // Also cancel any pending debounced callback so a stale handleChange call\n // can't overwrite the newly-applied controlled value.\n useEffect(() => {\n if (controlledValue !== undefined) {\n debouncedSearch.cancel();\n setInternalValue(controlledValue);\n }\n }, [controlledValue, debouncedSearch]);\n\n useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n setInternalValue(e.target.value);\n debouncedSearch(e.target.value);\n },\n [debouncedSearch],\n );\n\n const handleReset = useCallback(() => {\n setInternalValue('');\n onSearch('');\n debouncedSearch.cancel();\n }, [onSearch, debouncedSearch]);\n\n return (\n <SearchFieldBlock\n name={id}\n label={label}\n labelIsHidden\n placeholder={placeholder}\n value={internalValue}\n onChange={handleChange}\n onReset={handleReset}\n size={size}\n variant={variant}\n className=\"w-full max-w-120\"\n />\n );\n};\n"],"names":[],"mappings":";;;;;AAoBO,MAAM,aAAa,CAAC;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,GAAA;AAAA,EACb,IAAA;AAAA,EACA,KAAA,EAAO,eAAA;AAAA,EACP,OAAA,GAAU;AACZ,CAAA,KAAuB;AACrB,EAAA,MAAM,KAAK,KAAA,EAAM;AACjB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,QAAA,CAAS,mBAAmB,EAAE,CAAA;AAExE,EAAA,MAAM,eAAA,GAAkB,oBAAA,CAAqB,CAAC,GAAA,KAAgB;AAC5D,IAAA,QAAA,CAAS,GAAG,CAAA;AAAA,EACd,GAAG,UAAU,CAAA;AAKb,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,MAAA,eAAA,CAAgB,MAAA,EAAO;AACvB,MAAA,gBAAA,CAAiB,eAAe,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,eAAA,EAAiB,eAAe,CAAC,CAAA;AAErC,EAAA,SAAA,CAAU,MAAM,MAAM,eAAA,CAAgB,QAAO,EAAG,CAAC,eAAe,CAAC,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,CAAC,CAAA,KAA2C;AAC1C,MAAA,gBAAA,CAAiB,CAAA,CAAE,OAAO,KAAK,CAAA;AAC/B,MAAA,eAAA,CAAgB,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,eAAA,CAAgB,MAAA,EAAO;AAAA,EACzB,CAAA,EAAG,CAAC,QAAA,EAAU,eAAe,CAAC,CAAA;AAE9B,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,EAAA;AAAA,MACN,KAAA;AAAA,MACA,aAAA,EAAa,IAAA;AAAA,MACb,WAAA;AAAA,MACA,KAAA,EAAO,aAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MACT,IAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA,EAAU;AAAA;AAAA,GACZ;AAEJ;;;;"}
1
+ {"version":3,"file":"ListSearch.es.js","sources":["../../src/ds/components/ListSearch/list-search.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\nimport { SearchFieldBlock } from '@/ds/components/FormFieldBlocks/fields/search-field-block';\nimport type { InputProps } from '@/ds/components/Input';\nimport { useKeydown } from '@/lib/keyboard';\n\nexport type ListSearchProps = {\n onSearch: (search: string) => void;\n label: string;\n placeholder: string;\n debounceMs?: number;\n size?: InputProps['size'];\n /**\n * Optional controlled value. When provided, ListSearch stays in sync with this\n * prop — useful when the parent needs to clear the input programmatically\n * (e.g. from a Reset button). If omitted, ListSearch manages its own state.\n */\n value?: string;\n variant?: InputProps['variant'];\n /**\n * Opts out of the Cmd/Ctrl+Shift+F focus shortcut. Pass this on secondary\n * instances so two search fields on the same page don't fight over focus.\n */\n shortcutDisabled?: boolean;\n};\n\nexport const ListSearch = ({\n onSearch,\n label,\n placeholder,\n debounceMs = 300,\n size,\n value: controlledValue,\n variant = 'outline',\n shortcutDisabled = false,\n}: ListSearchProps) => {\n const id = useId();\n const [internalValue, setInternalValue] = useState(controlledValue ?? '');\n const inputRef = useRef<HTMLInputElement>(null);\n\n useKeydown({\n 'mod+shift+f': () => {\n if (shortcutDisabled) return;\n inputRef.current?.focus();\n inputRef.current?.select();\n },\n });\n\n const debouncedSearch = useDebouncedCallback((val: string) => {\n onSearch(val);\n }, debounceMs);\n\n // Sync internal state with controlled value (e.g. parent Reset clears it to '').\n // Also cancel any pending debounced callback so a stale handleChange call\n // can't overwrite the newly-applied controlled value.\n useEffect(() => {\n if (controlledValue !== undefined) {\n debouncedSearch.cancel();\n setInternalValue(controlledValue);\n }\n }, [controlledValue, debouncedSearch]);\n\n useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n setInternalValue(e.target.value);\n debouncedSearch(e.target.value);\n },\n [debouncedSearch],\n );\n\n const handleReset = useCallback(() => {\n setInternalValue('');\n onSearch('');\n debouncedSearch.cancel();\n }, [onSearch, debouncedSearch]);\n\n return (\n <SearchFieldBlock\n name={id}\n label={label}\n labelIsHidden\n placeholder={placeholder}\n value={internalValue}\n onChange={handleChange}\n onReset={handleReset}\n size={size}\n variant={variant}\n inputRef={inputRef}\n className=\"w-full max-w-120\"\n />\n );\n};\n"],"names":[],"mappings":";;;;;;AA0BO,MAAM,aAAa,CAAC;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,GAAA;AAAA,EACb,IAAA;AAAA,EACA,KAAA,EAAO,eAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,gBAAA,GAAmB;AACrB,CAAA,KAAuB;AACrB,EAAA,MAAM,KAAK,KAAA,EAAM;AACjB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,QAAA,CAAS,mBAAmB,EAAE,CAAA;AACxE,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAE9C,EAAA,UAAA,CAAW;AAAA,IACT,eAAe,MAAM;AACnB,MAAA,IAAI,gBAAA,EAAkB;AACtB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,QAAA,CAAS,SAAS,MAAA,EAAO;AAAA,IAC3B;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,oBAAA,CAAqB,CAAC,GAAA,KAAgB;AAC5D,IAAA,QAAA,CAAS,GAAG,CAAA;AAAA,EACd,GAAG,UAAU,CAAA;AAKb,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,MAAA,eAAA,CAAgB,MAAA,EAAO;AACvB,MAAA,gBAAA,CAAiB,eAAe,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,EAAG,CAAC,eAAA,EAAiB,eAAe,CAAC,CAAA;AAErC,EAAA,SAAA,CAAU,MAAM,MAAM,eAAA,CAAgB,QAAO,EAAG,CAAC,eAAe,CAAC,CAAA;AAEjE,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,CAAC,CAAA,KAA2C;AAC1C,MAAA,gBAAA,CAAiB,CAAA,CAAE,OAAO,KAAK,CAAA;AAC/B,MAAA,eAAA,CAAgB,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,eAAA,CAAgB,MAAA,EAAO;AAAA,EACzB,CAAA,EAAG,CAAC,QAAA,EAAU,eAAe,CAAC,CAAA;AAE9B,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,EAAA;AAAA,MACN,KAAA;AAAA,MACA,aAAA,EAAa,IAAA;AAAA,MACb,WAAA;AAAA,MACA,KAAA,EAAO,aAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MACT,IAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA,EAAU;AAAA;AAAA,GACZ;AAEJ;;;;"}
@@ -4,7 +4,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const logsDataList = require('../logs-data-list-Xayqbjw4.cjs');
6
6
  const dataListSkeleton = require('../data-list-skeleton-BHBSIQHN.cjs');
7
- require('react');
8
7
 
9
8
 
10
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"LogsDataList.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
1
+ {"version":3,"file":"LogsDataList.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -1,4 +1,3 @@
1
1
  export { L as LogsDataList } from '../logs-data-list-DRXJ89IZ.js';
2
2
  export { D as LogsDataListSkeleton } from '../data-list-skeleton-DDO_OE14.js';
3
- import 'react';
4
3
  //# sourceMappingURL=LogsDataList.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LogsDataList.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"LogsDataList.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -3,72 +3,10 @@
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const markdownRenderer = require('../markdown-renderer-BQugZq4m.cjs');
6
- const React = require('react');
6
+ const useReveal = require('../use-reveal-Sa456jZb.cjs');
7
+
7
8
 
8
- const BUFFER_MS = 1e3;
9
- const CORRECT_MS = 1e3;
10
- const FLOW_MS = 700;
11
- const EASE_MS = 400;
12
- const SLOWEST = 10;
13
- const FASTEST = 60;
14
- const MAX_LAG = 300;
15
- function measure(flow, now, gained) {
16
- const elapsed = Math.max(0, now - flow.at);
17
- flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1e3);
18
- flow.at = Math.max(flow.at, now);
19
- return flow.rate;
20
- }
21
- function prefersReducedMotion() {
22
- if (typeof window === "undefined" || !window.matchMedia) return false;
23
- return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
24
- }
25
- function wordStops(text) {
26
- const stops = [0];
27
- const word = /\S+/g;
28
- for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);
29
- return stops;
30
- }
31
- function useRevealedText(text, streaming) {
32
- const [calm] = React.useState(prefersReducedMotion);
33
- const stops = React.useMemo(() => wordStops(text), [text]);
34
- const words = stops.length - 1;
35
- const [landed, setLanded] = React.useState(() => streaming && !calm ? 0 : words);
36
- const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));
37
- if (shown !== landed) setLanded(shown);
38
- const chasing = shown < words;
39
- const goal = React.useRef(words);
40
- const cursor = React.useRef(shown);
41
- const flow = React.useRef({ rate: 0, at: 0 });
42
- const pace = React.useRef(SLOWEST);
43
- React.useEffect(() => {
44
- measure(flow.current, performance.now(), Math.max(0, words - goal.current));
45
- goal.current = words;
46
- if (cursor.current < shown || cursor.current > words) cursor.current = shown;
47
- });
48
- React.useEffect(() => {
49
- if (!chasing) return;
50
- let drawn = performance.now();
51
- let frame = requestAnimationFrame(function step(now) {
52
- const elapsed = Math.max(0, now - drawn);
53
- drawn = Math.max(drawn, now);
54
- const arriving = measure(flow.current, now, 0);
55
- const from = cursor.current;
56
- const behind = goal.current - from;
57
- if (behind > 0) {
58
- const held = arriving * BUFFER_MS / 1e3;
59
- const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + (behind - held) * 1e3 / CORRECT_MS));
60
- pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);
61
- cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + elapsed * pace.current / 1e3);
62
- if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));
63
- }
64
- frame = requestAnimationFrame(step);
65
- });
66
- return () => cancelAnimationFrame(frame);
67
- }, [chasing]);
68
- if (!chasing) return text;
69
- return text.slice(0, stops[shown]);
70
- }
71
9
 
72
10
  exports.MarkdownRenderer = markdownRenderer.MarkdownRenderer;
73
- exports.useRevealedText = useRevealedText;
11
+ exports.useRevealedText = useReveal.useRevealedText;
74
12
  //# sourceMappingURL=MarkdownRenderer.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownRenderer.cjs.js","sources":["../../src/ds/components/MarkdownRenderer/use-reveal.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n // rAF timestamps and performance.now() are sampled at different points of a\n // frame, so a fresh loop can read time slightly behind the last deposit.\n const elapsed = Math.max(0, now - flow.at);\n flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = Math.max(flow.at, now);\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * The reply it paces is whatever the caller hands it, so a caller with more than\n * prose to lay down — a tool row between two paragraphs — paces the whole of it\n * from one place and draws the rest against the same cursor.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useRevealedText(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? 0 : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = Math.max(0, now - drawn);\n drawn = Math.max(drawn, now);\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n"],"names":["useState","useMemo","useRef","useEffect"],"mappings":"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"}
1
+ {"version":3,"file":"MarkdownRenderer.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -1,69 +1,3 @@
1
1
  export { M as MarkdownRenderer } from '../markdown-renderer-LOqipQki.js';
2
- import { useState, useMemo, useRef, useEffect } from 'react';
3
-
4
- const BUFFER_MS = 1e3;
5
- const CORRECT_MS = 1e3;
6
- const FLOW_MS = 700;
7
- const EASE_MS = 400;
8
- const SLOWEST = 10;
9
- const FASTEST = 60;
10
- const MAX_LAG = 300;
11
- function measure(flow, now, gained) {
12
- const elapsed = Math.max(0, now - flow.at);
13
- flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1e3);
14
- flow.at = Math.max(flow.at, now);
15
- return flow.rate;
16
- }
17
- function prefersReducedMotion() {
18
- if (typeof window === "undefined" || !window.matchMedia) return false;
19
- return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
20
- }
21
- function wordStops(text) {
22
- const stops = [0];
23
- const word = /\S+/g;
24
- for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);
25
- return stops;
26
- }
27
- function useRevealedText(text, streaming) {
28
- const [calm] = useState(prefersReducedMotion);
29
- const stops = useMemo(() => wordStops(text), [text]);
30
- const words = stops.length - 1;
31
- const [landed, setLanded] = useState(() => streaming && !calm ? 0 : words);
32
- const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));
33
- if (shown !== landed) setLanded(shown);
34
- const chasing = shown < words;
35
- const goal = useRef(words);
36
- const cursor = useRef(shown);
37
- const flow = useRef({ rate: 0, at: 0 });
38
- const pace = useRef(SLOWEST);
39
- useEffect(() => {
40
- measure(flow.current, performance.now(), Math.max(0, words - goal.current));
41
- goal.current = words;
42
- if (cursor.current < shown || cursor.current > words) cursor.current = shown;
43
- });
44
- useEffect(() => {
45
- if (!chasing) return;
46
- let drawn = performance.now();
47
- let frame = requestAnimationFrame(function step(now) {
48
- const elapsed = Math.max(0, now - drawn);
49
- drawn = Math.max(drawn, now);
50
- const arriving = measure(flow.current, now, 0);
51
- const from = cursor.current;
52
- const behind = goal.current - from;
53
- if (behind > 0) {
54
- const held = arriving * BUFFER_MS / 1e3;
55
- const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + (behind - held) * 1e3 / CORRECT_MS));
56
- pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);
57
- cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + elapsed * pace.current / 1e3);
58
- if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));
59
- }
60
- frame = requestAnimationFrame(step);
61
- });
62
- return () => cancelAnimationFrame(frame);
63
- }, [chasing]);
64
- if (!chasing) return text;
65
- return text.slice(0, stops[shown]);
66
- }
67
-
68
- export { useRevealedText };
2
+ export { u as useRevealedText } from '../use-reveal-d77hxHz9.js';
69
3
  //# sourceMappingURL=MarkdownRenderer.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownRenderer.es.js","sources":["../../src/ds/components/MarkdownRenderer/use-reveal.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n // rAF timestamps and performance.now() are sampled at different points of a\n // frame, so a fresh loop can read time slightly behind the last deposit.\n const elapsed = Math.max(0, now - flow.at);\n flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = Math.max(flow.at, now);\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * The reply it paces is whatever the caller hands it, so a caller with more than\n * prose to lay down — a tool row between two paragraphs — paces the whole of it\n * from one place and draws the rest against the same cursor.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useRevealedText(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? 0 : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = Math.max(0, now - drawn);\n drawn = Math.max(drawn, now);\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MarkdownRenderer.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const useReveal = require('../../use-reveal-Sa456jZb.cjs');
6
+
7
+ const PASSAGE = "\n\n";
8
+ const ROW_MARK = Array.from({ length: 6 }, () => "").join(" ");
9
+ function partProse(part) {
10
+ if (part.type === "text") return part.text;
11
+ if (part.type === "reasoning") return part.reasoning;
12
+ return void 0;
13
+ }
14
+ function messageScript(parts) {
15
+ return parts.map((part) => partProse(part) ?? ROW_MARK).join(PASSAGE);
16
+ }
17
+ function revealedParts(parts, shown) {
18
+ const script = messageScript(parts);
19
+ if (shown.length >= script.length) return parts;
20
+ const revealed = [];
21
+ let read = 0;
22
+ for (const part of parts) {
23
+ const start = read === 0 ? 0 : read + PASSAGE.length;
24
+ if (part.type !== "text" && part.type !== "reasoning") {
25
+ read = start + ROW_MARK.length;
26
+ if (shown.length < read) break;
27
+ revealed.push(part);
28
+ continue;
29
+ }
30
+ const written = part.type === "text" ? part.text : part.reasoning;
31
+ read = start + written.length;
32
+ const text = shown.slice(start, read);
33
+ if (text === written) {
34
+ revealed.push(part);
35
+ continue;
36
+ }
37
+ if (text) revealed.push(part.type === "text" ? { ...part, text } : { ...part, reasoning: text });
38
+ break;
39
+ }
40
+ return revealed;
41
+ }
42
+ function useRevealedParts(parts, streaming) {
43
+ const shown = useReveal.useRevealedText(messageScript(parts), streaming);
44
+ return revealedParts(parts, shown);
45
+ }
46
+
47
+ exports.messageScript = messageScript;
48
+ exports.revealedParts = revealedParts;
49
+ exports.useRevealedParts = useRevealedParts;
50
+ //# sourceMappingURL=message-reveal.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-reveal.cjs.js","sources":["../../../src/ds/components/ai/message-reveal/message-reveal.ts"],"sourcesContent":["import type { MastraDBMessage } from '@mastra/core/agent/message-list';\n\nimport { useRevealedText } from '../../MarkdownRenderer/use-reveal';\n\ntype MessagePart = MastraDBMessage['content']['parts'][number];\n\n/** What separates two passages of prose that were streamed as separate blocks. */\nconst PASSAGE = '\\n\\n';\n\n/**\n * A part that is not prose, written into the reveal's script as words so it takes a\n * beat on the same clock: a burst of parallel tool calls cascades in row by row, at\n * the pace the reply is moving, instead of landing as one block.\n */\nconst ROW_MARK = Array.from({ length: 6 }, () => '').join(' ');\n\n/**\n * The words a part was written as, for the kinds the model writes word by word.\n * Reasoning streams delta by delta exactly like prose, so its passage takes its\n * words' time on the clock rather than one row's beat — a beat would hold the\n * block back whole, then let it land at once and grow unpaced.\n */\nfunction partProse(part: MessagePart): string | undefined {\n if (part.type === 'text') return part.text;\n if (part.type === 'reasoning') return part.reasoning;\n return undefined;\n}\n\n/** What the reveal paces: the whole message, rows and cards written in as beats between the prose. */\nexport function messageScript(parts: MessagePart[]): string {\n return parts.map(part => partProse(part) ?? ROW_MARK).join(PASSAGE);\n}\n\n/**\n * The parts of a message a reveal has reached, `shown` being a prefix of the script.\n *\n * A reply is not only prose: a tool row, a card, a reasoning block sit between its\n * passages, and they were written in that order. Pacing the prose alone would lay a\n * sentence down word by word while the row that follows it is already on screen — so\n * every part waits its turn on the one clock, and the reader is handed the answer in\n * the order it was written.\n */\nexport function revealedParts(parts: MessagePart[], shown: string): MessagePart[] {\n const script = messageScript(parts);\n if (shown.length >= script.length) return parts;\n\n const revealed: MessagePart[] = [];\n let read = 0;\n\n for (const part of parts) {\n const start = read === 0 ? 0 : read + PASSAGE.length;\n\n if (part.type !== 'text' && part.type !== 'reasoning') {\n read = start + ROW_MARK.length;\n if (shown.length < read) break;\n revealed.push(part);\n continue;\n }\n\n const written = part.type === 'text' ? part.text : part.reasoning;\n read = start + written.length;\n\n const text = shown.slice(start, read);\n if (text === written) {\n revealed.push(part);\n continue;\n }\n\n if (text) revealed.push(part.type === 'text' ? { ...part, text } : { ...part, reasoning: text });\n break;\n }\n\n return revealed;\n}\n\n/**\n * A message's parts as far as the reveal has laid them down. Hand the result to\n * `MessageFactory` in place of the message's own parts and the whole reply — prose,\n * reasoning, tool rows, cards — arrives at the pace it was written, from one clock,\n * without a renderer having to know a reveal is running.\n */\nexport function useRevealedParts(parts: MessagePart[], streaming: boolean): MessagePart[] {\n const shown = useRevealedText(messageScript(parts), streaming);\n\n return revealedParts(parts, shown);\n}\n"],"names":["useRevealedText"],"mappings":";;;;;;AAOA,MAAM,OAAA,GAAU,MAAA;AAOhB,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAE,EAAG,MAAM,GAAG,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAQ9D,SAAS,UAAU,IAAA,EAAuC;AACxD,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA,CAAK,IAAA;AACtC,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,WAAA,EAAa,OAAO,IAAA,CAAK,SAAA;AAC3C,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,cAAc,KAAA,EAA8B;AAC1D,EAAA,OAAO,KAAA,CAAM,IAAI,CAAA,IAAA,KAAQ,SAAA,CAAU,IAAI,CAAA,IAAK,QAAQ,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA;AACpE;AAWO,SAAS,aAAA,CAAc,OAAsB,KAAA,EAA8B;AAChF,EAAA,MAAM,MAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,IAAI,KAAA,CAAM,MAAA,IAAU,MAAA,CAAO,MAAA,EAAQ,OAAO,KAAA;AAE1C,EAAA,MAAM,WAA0B,EAAC;AACjC,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,KAAA,GAAQ,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,OAAO,OAAA,CAAQ,MAAA;AAE9C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,WAAA,EAAa;AACrD,MAAA,IAAA,GAAO,QAAQ,QAAA,CAAS,MAAA;AACxB,MAAA,IAAI,KAAA,CAAM,SAAS,IAAA,EAAM;AACzB,MAAA,QAAA,CAAS,KAAK,IAAI,CAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,IAAA,CAAK,IAAA,KAAS,MAAA,GAAS,IAAA,CAAK,OAAO,IAAA,CAAK,SAAA;AACxD,IAAA,IAAA,GAAO,QAAQ,OAAA,CAAQ,MAAA;AAEvB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,IAAI,CAAA;AACpC,IAAA,IAAI,SAAS,OAAA,EAAS;AACpB,MAAA,QAAA,CAAS,KAAK,IAAI,CAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,MAAM,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,IAAA,KAAS,SAAS,EAAE,GAAG,IAAA,EAAM,IAAA,KAAS,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,MAAM,CAAA;AAC/F,IAAA;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAQO,SAAS,gBAAA,CAAiB,OAAsB,SAAA,EAAmC;AACxF,EAAA,MAAM,KAAA,GAAQA,yBAAA,CAAgB,aAAA,CAAc,KAAK,GAAG,SAAS,CAAA;AAE7D,EAAA,OAAO,aAAA,CAAc,OAAO,KAAK,CAAA;AACnC;;;;;;"}
@@ -0,0 +1,2 @@
1
+ export * from '../../src/ds/components/ai/message-reveal/index'
2
+ export {}
@@ -0,0 +1,44 @@
1
+ import { u as useRevealedText } from '../../use-reveal-d77hxHz9.js';
2
+
3
+ const PASSAGE = "\n\n";
4
+ const ROW_MARK = Array.from({ length: 6 }, () => "").join(" ");
5
+ function partProse(part) {
6
+ if (part.type === "text") return part.text;
7
+ if (part.type === "reasoning") return part.reasoning;
8
+ return void 0;
9
+ }
10
+ function messageScript(parts) {
11
+ return parts.map((part) => partProse(part) ?? ROW_MARK).join(PASSAGE);
12
+ }
13
+ function revealedParts(parts, shown) {
14
+ const script = messageScript(parts);
15
+ if (shown.length >= script.length) return parts;
16
+ const revealed = [];
17
+ let read = 0;
18
+ for (const part of parts) {
19
+ const start = read === 0 ? 0 : read + PASSAGE.length;
20
+ if (part.type !== "text" && part.type !== "reasoning") {
21
+ read = start + ROW_MARK.length;
22
+ if (shown.length < read) break;
23
+ revealed.push(part);
24
+ continue;
25
+ }
26
+ const written = part.type === "text" ? part.text : part.reasoning;
27
+ read = start + written.length;
28
+ const text = shown.slice(start, read);
29
+ if (text === written) {
30
+ revealed.push(part);
31
+ continue;
32
+ }
33
+ if (text) revealed.push(part.type === "text" ? { ...part, text } : { ...part, reasoning: text });
34
+ break;
35
+ }
36
+ return revealed;
37
+ }
38
+ function useRevealedParts(parts, streaming) {
39
+ const shown = useRevealedText(messageScript(parts), streaming);
40
+ return revealedParts(parts, shown);
41
+ }
42
+
43
+ export { messageScript, revealedParts, useRevealedParts };
44
+ //# sourceMappingURL=message-reveal.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-reveal.es.js","sources":["../../../src/ds/components/ai/message-reveal/message-reveal.ts"],"sourcesContent":["import type { MastraDBMessage } from '@mastra/core/agent/message-list';\n\nimport { useRevealedText } from '../../MarkdownRenderer/use-reveal';\n\ntype MessagePart = MastraDBMessage['content']['parts'][number];\n\n/** What separates two passages of prose that were streamed as separate blocks. */\nconst PASSAGE = '\\n\\n';\n\n/**\n * A part that is not prose, written into the reveal's script as words so it takes a\n * beat on the same clock: a burst of parallel tool calls cascades in row by row, at\n * the pace the reply is moving, instead of landing as one block.\n */\nconst ROW_MARK = Array.from({ length: 6 }, () => '').join(' ');\n\n/**\n * The words a part was written as, for the kinds the model writes word by word.\n * Reasoning streams delta by delta exactly like prose, so its passage takes its\n * words' time on the clock rather than one row's beat — a beat would hold the\n * block back whole, then let it land at once and grow unpaced.\n */\nfunction partProse(part: MessagePart): string | undefined {\n if (part.type === 'text') return part.text;\n if (part.type === 'reasoning') return part.reasoning;\n return undefined;\n}\n\n/** What the reveal paces: the whole message, rows and cards written in as beats between the prose. */\nexport function messageScript(parts: MessagePart[]): string {\n return parts.map(part => partProse(part) ?? ROW_MARK).join(PASSAGE);\n}\n\n/**\n * The parts of a message a reveal has reached, `shown` being a prefix of the script.\n *\n * A reply is not only prose: a tool row, a card, a reasoning block sit between its\n * passages, and they were written in that order. Pacing the prose alone would lay a\n * sentence down word by word while the row that follows it is already on screen — so\n * every part waits its turn on the one clock, and the reader is handed the answer in\n * the order it was written.\n */\nexport function revealedParts(parts: MessagePart[], shown: string): MessagePart[] {\n const script = messageScript(parts);\n if (shown.length >= script.length) return parts;\n\n const revealed: MessagePart[] = [];\n let read = 0;\n\n for (const part of parts) {\n const start = read === 0 ? 0 : read + PASSAGE.length;\n\n if (part.type !== 'text' && part.type !== 'reasoning') {\n read = start + ROW_MARK.length;\n if (shown.length < read) break;\n revealed.push(part);\n continue;\n }\n\n const written = part.type === 'text' ? part.text : part.reasoning;\n read = start + written.length;\n\n const text = shown.slice(start, read);\n if (text === written) {\n revealed.push(part);\n continue;\n }\n\n if (text) revealed.push(part.type === 'text' ? { ...part, text } : { ...part, reasoning: text });\n break;\n }\n\n return revealed;\n}\n\n/**\n * A message's parts as far as the reveal has laid them down. Hand the result to\n * `MessageFactory` in place of the message's own parts and the whole reply — prose,\n * reasoning, tool rows, cards — arrives at the pace it was written, from one clock,\n * without a renderer having to know a reveal is running.\n */\nexport function useRevealedParts(parts: MessagePart[], streaming: boolean): MessagePart[] {\n const shown = useRevealedText(messageScript(parts), streaming);\n\n return revealedParts(parts, shown);\n}\n"],"names":[],"mappings":";;AAOA,MAAM,OAAA,GAAU,MAAA;AAOhB,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAE,EAAG,MAAM,GAAG,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAQ9D,SAAS,UAAU,IAAA,EAAuC;AACxD,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA,CAAK,IAAA;AACtC,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,WAAA,EAAa,OAAO,IAAA,CAAK,SAAA;AAC3C,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,cAAc,KAAA,EAA8B;AAC1D,EAAA,OAAO,KAAA,CAAM,IAAI,CAAA,IAAA,KAAQ,SAAA,CAAU,IAAI,CAAA,IAAK,QAAQ,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA;AACpE;AAWO,SAAS,aAAA,CAAc,OAAsB,KAAA,EAA8B;AAChF,EAAA,MAAM,MAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,IAAI,KAAA,CAAM,MAAA,IAAU,MAAA,CAAO,MAAA,EAAQ,OAAO,KAAA;AAE1C,EAAA,MAAM,WAA0B,EAAC;AACjC,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,KAAA,GAAQ,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,OAAO,OAAA,CAAQ,MAAA;AAE9C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,WAAA,EAAa;AACrD,MAAA,IAAA,GAAO,QAAQ,QAAA,CAAS,MAAA;AACxB,MAAA,IAAI,KAAA,CAAM,SAAS,IAAA,EAAM;AACzB,MAAA,QAAA,CAAS,KAAK,IAAI,CAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,IAAA,CAAK,IAAA,KAAS,MAAA,GAAS,IAAA,CAAK,OAAO,IAAA,CAAK,SAAA;AACxD,IAAA,IAAA,GAAO,QAAQ,OAAA,CAAQ,MAAA;AAEvB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,IAAI,CAAA;AACpC,IAAA,IAAI,SAAS,OAAA,EAAS;AACpB,MAAA,QAAA,CAAS,KAAK,IAAI,CAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,MAAM,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,IAAA,KAAS,SAAS,EAAE,GAAG,IAAA,EAAM,IAAA,KAAS,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,MAAM,CAAA;AAC/F,IAAA;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAQO,SAAS,gBAAA,CAAiB,OAAsB,SAAA,EAAmC;AACxF,EAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,aAAA,CAAc,KAAK,GAAG,SAAS,CAAA;AAE7D,EAAA,OAAO,aAAA,CAAc,OAAO,KAAK,CAAA;AACnC;;;;"}
@@ -16,7 +16,7 @@ const buttonsGroup = require('./buttons-group-w9QHUGVh.cjs');
16
16
  const copyButton = require('./copy-button-D1BF_G8A.cjs');
17
17
  const utils_cn = require('./cn-vA5sWo9W.cjs');
18
18
  const dialog = require('./dialog-DecmYFeJ.cjs');
19
- const searchFieldBlock = require('./search-field-block-BqRM53jf.cjs');
19
+ const searchFieldBlock = require('./search-field-block-CjCIzUhN.cjs');
20
20
  const themeProvider = require('./theme-provider-aO5-jZVp.cjs');
21
21
 
22
22
  function DataPanelSectionHeading({ icon, className, children }) {
@@ -332,4 +332,4 @@ function containsInnerNewline(obj) {
332
332
 
333
333
  exports.DataCodeSection = DataCodeSection;
334
334
  exports.DataPanelSectionHeading = DataPanelSectionHeading;
335
- //# sourceMappingURL=data-code-section-sK4cZuA-.cjs.map
335
+ //# sourceMappingURL=data-code-section-C3ZRkULz.cjs.map