@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.
- package/CHANGELOG.md +58 -0
- package/LICENSE.md +6 -4
- package/dist/components/DataCodeSection.cjs.js +1 -1
- package/dist/components/DataCodeSection.es.js +1 -1
- package/dist/components/DataPanel.cjs.js +1 -1
- package/dist/components/DataPanel.es.js +1 -1
- package/dist/components/FormFieldBlocks.cjs.js +1 -1
- package/dist/components/FormFieldBlocks.es.js +1 -1
- package/dist/components/ListSearch.cjs.js +13 -2
- package/dist/components/ListSearch.cjs.js.map +1 -1
- package/dist/components/ListSearch.es.js +14 -3
- package/dist/components/ListSearch.es.js.map +1 -1
- package/dist/components/LogsDataList.cjs.js +0 -1
- package/dist/components/LogsDataList.cjs.js.map +1 -1
- package/dist/components/LogsDataList.es.js +0 -1
- package/dist/components/LogsDataList.es.js.map +1 -1
- package/dist/components/MarkdownRenderer.cjs.js +3 -65
- package/dist/components/MarkdownRenderer.cjs.js.map +1 -1
- package/dist/components/MarkdownRenderer.es.js +1 -67
- package/dist/components/MarkdownRenderer.es.js.map +1 -1
- package/dist/components/ai/message-reveal.cjs.js +50 -0
- package/dist/components/ai/message-reveal.cjs.js.map +1 -0
- package/dist/components/ai/message-reveal.d.ts +2 -0
- package/dist/components/ai/message-reveal.es.js +44 -0
- package/dist/components/ai/message-reveal.es.js.map +1 -0
- package/dist/{data-code-section-sK4cZuA-.cjs → data-code-section-C3ZRkULz.cjs} +2 -2
- package/dist/{data-code-section-sK4cZuA-.cjs.map → data-code-section-C3ZRkULz.cjs.map} +1 -1
- package/dist/{data-code-section-g1jBtzwR.js → data-code-section-CSt_ZuUP.js} +2 -2
- package/dist/{data-code-section-g1jBtzwR.js.map → data-code-section-CSt_ZuUP.js.map} +1 -1
- package/dist/{data-panel-B3AECYLW.cjs → data-panel-DHNc5Y4L.cjs} +2 -2
- package/dist/{data-panel-B3AECYLW.cjs.map → data-panel-DHNc5Y4L.cjs.map} +1 -1
- package/dist/{data-panel-B527Q_Zh.js → data-panel-DJpAfEsG.js} +2 -2
- package/dist/{data-panel-B527Q_Zh.js.map → data-panel-DJpAfEsG.js.map} +1 -1
- package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
- package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js.map +1 -1
- package/dist/domains/traces/components/timeline-name-col.es.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.es.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +44 -9
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +45 -10
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-timeline.cjs.js +18 -14
- package/dist/domains/traces/components/trace-timeline.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-timeline.es.js +18 -14
- package/dist/domains/traces/components/trace-timeline.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-branch.cjs.js +4 -0
- package/dist/domains/traces/hooks/use-branch.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-branch.es.js +4 -0
- package/dist/domains/traces/hooks/use-branch.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js +4 -0
- package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-light-spans.es.js +4 -0
- package/dist/domains/traces/hooks/use-trace-light-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js +2 -2
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js +2 -2
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-search.cjs.js +21 -0
- package/dist/domains/traces/hooks/use-trace-search.cjs.js.map +1 -0
- package/dist/domains/traces/hooks/use-trace-search.d.ts +2 -0
- package/dist/domains/traces/hooks/use-trace-search.es.js +17 -0
- package/dist/domains/traces/hooks/use-trace-search.es.js.map +1 -0
- package/dist/domains/traces/hooks/use-trace-spans.cjs.js +11 -1
- package/dist/domains/traces/hooks/use-trace-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-spans.es.js +11 -1
- package/dist/domains/traces/hooks/use-trace-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks.cjs.js +2 -0
- package/dist/domains/traces/hooks.cjs.js.map +1 -1
- package/dist/domains/traces/hooks.es.js +1 -0
- package/dist/domains/traces/hooks.es.js.map +1 -1
- package/dist/domains/traces/types.cjs.js.map +1 -1
- package/dist/domains/traces/types.es.js.map +1 -1
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js +47 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js.map +1 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +2 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js +43 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js.map +1 -0
- package/dist/domains/traces/utils/flatten-to-search-text.cjs.js +78 -0
- package/dist/domains/traces/utils/flatten-to-search-text.cjs.js.map +1 -0
- package/dist/domains/traces/utils/flatten-to-search-text.d.ts +2 -0
- package/dist/domains/traces/utils/flatten-to-search-text.es.js +74 -0
- package/dist/domains/traces/utils/flatten-to-search-text.es.js.map +1 -0
- package/dist/domains/traces/utils/to-searchable-spans.cjs.js +22 -0
- package/dist/domains/traces/utils/to-searchable-spans.cjs.js.map +1 -0
- package/dist/domains/traces/utils/to-searchable-spans.d.ts +2 -0
- package/dist/domains/traces/utils/to-searchable-spans.es.js +17 -0
- package/dist/domains/traces/utils/to-searchable-spans.es.js.map +1 -0
- package/dist/domains/traces/utils.cjs.js +7 -0
- package/dist/domains/traces/utils.cjs.js.map +1 -1
- package/dist/domains/traces/utils.es.js +3 -0
- package/dist/domains/traces/utils.es.js.map +1 -1
- package/dist/domains/traces.cjs.js +9 -0
- package/dist/domains/traces.cjs.js.map +1 -1
- package/dist/domains/traces.es.js +4 -0
- package/dist/domains/traces.es.js.map +1 -1
- package/dist/ee/topics/components/topic-trace-details-panel.cjs.js +2 -2
- package/dist/ee/topics/components/topic-trace-details-panel.cjs.js.map +1 -1
- package/dist/ee/topics/components/topic-trace-details-panel.es.js +2 -2
- package/dist/ee/topics/components/topic-trace-details-panel.es.js.map +1 -1
- package/dist/hooks/use-text-highlight.cjs.js +68 -0
- package/dist/hooks/use-text-highlight.cjs.js.map +1 -0
- package/dist/hooks/use-text-highlight.d.ts +2 -0
- package/dist/hooks/use-text-highlight.es.js +64 -0
- package/dist/hooks/use-text-highlight.es.js.map +1 -0
- package/dist/{search-field-block-BqRM53jf.cjs → search-field-block-CjCIzUhN.cjs} +8 -3
- package/dist/search-field-block-CjCIzUhN.cjs.map +1 -0
- package/dist/{search-field-block-CgrC6f9t.js → search-field-block-DoNywsJC.js} +8 -3
- package/dist/search-field-block-DoNywsJC.js.map +1 -0
- package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +2 -2
- package/dist/src/domains/traces/components/trace-timeline.d.ts +4 -2
- package/dist/src/domains/traces/hooks/index.d.ts +1 -0
- package/dist/src/domains/traces/hooks/use-branch.d.ts +2 -2
- package/dist/src/domains/traces/hooks/use-trace-light-spans.d.ts +2 -2
- package/dist/src/domains/traces/hooks/use-trace-or-branch-spans.d.ts +5 -2
- package/dist/src/domains/traces/hooks/use-trace-search.d.ts +27 -0
- package/dist/src/domains/traces/hooks/use-trace-spans.d.ts +11 -2
- package/dist/src/domains/traces/types.d.ts +16 -0
- package/dist/src/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +19 -0
- package/dist/src/domains/traces/utils/flatten-to-search-text.d.ts +25 -0
- package/dist/src/domains/traces/utils/index.d.ts +3 -0
- package/dist/src/domains/traces/utils/to-searchable-spans.d.ts +41 -0
- package/dist/src/ds/components/Arrival/arrival.stories.d.ts +6 -0
- package/dist/src/ds/components/Card/card.stories.d.ts +8 -0
- package/dist/src/ds/components/Columns/columns.stories.d.ts +7 -0
- package/dist/src/ds/components/DataDetailsPanel/data-details-panel.stories.d.ts +9 -0
- package/dist/src/ds/components/DataFilter/select-data-filter.stories.d.ts +8 -0
- package/dist/src/ds/components/DateRangeTimeline/date-range-timeline.stories.d.ts +8 -0
- package/dist/src/ds/components/ErrorState/error-state.stories.d.ts +7 -0
- package/dist/src/ds/components/FormFieldBlocks/fields/search-field-block.d.ts +4 -1
- package/dist/src/ds/components/ListSearch/list-search.d.ts +6 -1
- package/dist/src/ds/components/ListSearch/list-search.stories.d.ts +7 -0
- package/dist/src/ds/components/LogsDataList/logs-data-list.stories.d.ts +8 -0
- package/dist/src/ds/components/MessageScroller/message-scroller.stories.d.ts +7 -0
- package/dist/src/ds/components/MetricsLineChart/metrics-line-chart.stories.d.ts +8 -0
- package/dist/src/ds/components/PageHeader/page-header.stories.d.ts +8 -0
- package/dist/src/ds/components/PageLayout/page-layout.stories.d.ts +8 -0
- package/dist/src/ds/components/PendingIndicator/pending-indicator.stories.d.ts +7 -0
- package/dist/src/ds/components/PermissionDenied/permission-denied.stories.d.ts +8 -0
- package/dist/src/ds/components/PrevNextNav/prev-next-nav.stories.d.ts +8 -0
- package/dist/src/ds/components/SessionExpired/session-expired.stories.d.ts +7 -0
- package/dist/src/ds/components/Shimmer/shimmer.stories.d.ts +7 -0
- package/dist/src/ds/components/StatusBadge/status-badge.stories.d.ts +8 -0
- package/dist/src/ds/components/ThreadList/thread-list.stories.d.ts +8 -0
- package/dist/src/ds/components/ThreadRail/thread-rail.stories.d.ts +7 -0
- package/dist/src/ds/components/TokenBudget/token-budget.stories.d.ts +8 -0
- package/dist/src/ds/components/ai/message-reveal/index.d.ts +1 -0
- package/dist/src/ds/components/ai/message-reveal/message-reveal.d.ts +22 -0
- package/dist/src/hooks/use-text-highlight.d.ts +18 -0
- package/dist/src/test/highlight-api.d.ts +28 -0
- package/dist/style.css +80 -0
- package/dist/use-reveal-Sa456jZb.cjs +70 -0
- package/dist/use-reveal-Sa456jZb.cjs.map +1 -0
- package/dist/use-reveal-d77hxHz9.js +68 -0
- package/dist/use-reveal-d77hxHz9.js.map +1 -0
- package/dist/use-text-highlight.css +8 -0
- package/package.json +8 -8
- package/dist/search-field-block-BqRM53jf.cjs.map +0 -1
- package/dist/search-field-block-CgrC6f9t.js.map +0 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const React = require('react');
|
|
4
|
+
|
|
5
|
+
const BUFFER_MS = 1e3;
|
|
6
|
+
const CORRECT_MS = 1e3;
|
|
7
|
+
const FLOW_MS = 700;
|
|
8
|
+
const EASE_MS = 400;
|
|
9
|
+
const SLOWEST = 10;
|
|
10
|
+
const FASTEST = 60;
|
|
11
|
+
const MAX_LAG = 300;
|
|
12
|
+
function measure(flow, now, gained) {
|
|
13
|
+
const elapsed = Math.max(0, now - flow.at);
|
|
14
|
+
flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1e3);
|
|
15
|
+
flow.at = Math.max(flow.at, now);
|
|
16
|
+
return flow.rate;
|
|
17
|
+
}
|
|
18
|
+
function prefersReducedMotion() {
|
|
19
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
20
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
21
|
+
}
|
|
22
|
+
function wordStops(text) {
|
|
23
|
+
const stops = [0];
|
|
24
|
+
const word = /\S+/g;
|
|
25
|
+
for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);
|
|
26
|
+
return stops;
|
|
27
|
+
}
|
|
28
|
+
function useRevealedText(text, streaming) {
|
|
29
|
+
const [calm] = React.useState(prefersReducedMotion);
|
|
30
|
+
const stops = React.useMemo(() => wordStops(text), [text]);
|
|
31
|
+
const words = stops.length - 1;
|
|
32
|
+
const [landed, setLanded] = React.useState(() => streaming && !calm ? 0 : words);
|
|
33
|
+
const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));
|
|
34
|
+
if (shown !== landed) setLanded(shown);
|
|
35
|
+
const chasing = shown < words;
|
|
36
|
+
const goal = React.useRef(words);
|
|
37
|
+
const cursor = React.useRef(shown);
|
|
38
|
+
const flow = React.useRef({ rate: 0, at: 0 });
|
|
39
|
+
const pace = React.useRef(SLOWEST);
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
measure(flow.current, performance.now(), Math.max(0, words - goal.current));
|
|
42
|
+
goal.current = words;
|
|
43
|
+
if (cursor.current < shown || cursor.current > words) cursor.current = shown;
|
|
44
|
+
});
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
if (!chasing) return;
|
|
47
|
+
let drawn = performance.now();
|
|
48
|
+
let frame = requestAnimationFrame(function step(now) {
|
|
49
|
+
const elapsed = Math.max(0, now - drawn);
|
|
50
|
+
drawn = Math.max(drawn, now);
|
|
51
|
+
const arriving = measure(flow.current, now, 0);
|
|
52
|
+
const from = cursor.current;
|
|
53
|
+
const behind = goal.current - from;
|
|
54
|
+
if (behind > 0) {
|
|
55
|
+
const held = arriving * BUFFER_MS / 1e3;
|
|
56
|
+
const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + (behind - held) * 1e3 / CORRECT_MS));
|
|
57
|
+
pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);
|
|
58
|
+
cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + elapsed * pace.current / 1e3);
|
|
59
|
+
if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));
|
|
60
|
+
}
|
|
61
|
+
frame = requestAnimationFrame(step);
|
|
62
|
+
});
|
|
63
|
+
return () => cancelAnimationFrame(frame);
|
|
64
|
+
}, [chasing]);
|
|
65
|
+
if (!chasing) return text;
|
|
66
|
+
return text.slice(0, stops[shown]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.useRevealedText = useRevealedText;
|
|
70
|
+
//# sourceMappingURL=use-reveal-Sa456jZb.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-reveal-Sa456jZb.cjs","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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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useState, useMemo, useRef, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const BUFFER_MS = 1e3;
|
|
4
|
+
const CORRECT_MS = 1e3;
|
|
5
|
+
const FLOW_MS = 700;
|
|
6
|
+
const EASE_MS = 400;
|
|
7
|
+
const SLOWEST = 10;
|
|
8
|
+
const FASTEST = 60;
|
|
9
|
+
const MAX_LAG = 300;
|
|
10
|
+
function measure(flow, now, gained) {
|
|
11
|
+
const elapsed = Math.max(0, now - flow.at);
|
|
12
|
+
flow.rate = flow.rate * Math.exp(-elapsed / FLOW_MS) + gained / (FLOW_MS / 1e3);
|
|
13
|
+
flow.at = Math.max(flow.at, now);
|
|
14
|
+
return flow.rate;
|
|
15
|
+
}
|
|
16
|
+
function prefersReducedMotion() {
|
|
17
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
18
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
19
|
+
}
|
|
20
|
+
function wordStops(text) {
|
|
21
|
+
const stops = [0];
|
|
22
|
+
const word = /\S+/g;
|
|
23
|
+
for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);
|
|
24
|
+
return stops;
|
|
25
|
+
}
|
|
26
|
+
function useRevealedText(text, streaming) {
|
|
27
|
+
const [calm] = useState(prefersReducedMotion);
|
|
28
|
+
const stops = useMemo(() => wordStops(text), [text]);
|
|
29
|
+
const words = stops.length - 1;
|
|
30
|
+
const [landed, setLanded] = useState(() => streaming && !calm ? 0 : words);
|
|
31
|
+
const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));
|
|
32
|
+
if (shown !== landed) setLanded(shown);
|
|
33
|
+
const chasing = shown < words;
|
|
34
|
+
const goal = useRef(words);
|
|
35
|
+
const cursor = useRef(shown);
|
|
36
|
+
const flow = useRef({ rate: 0, at: 0 });
|
|
37
|
+
const pace = useRef(SLOWEST);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
measure(flow.current, performance.now(), Math.max(0, words - goal.current));
|
|
40
|
+
goal.current = words;
|
|
41
|
+
if (cursor.current < shown || cursor.current > words) cursor.current = shown;
|
|
42
|
+
});
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!chasing) return;
|
|
45
|
+
let drawn = performance.now();
|
|
46
|
+
let frame = requestAnimationFrame(function step(now) {
|
|
47
|
+
const elapsed = Math.max(0, now - drawn);
|
|
48
|
+
drawn = Math.max(drawn, now);
|
|
49
|
+
const arriving = measure(flow.current, now, 0);
|
|
50
|
+
const from = cursor.current;
|
|
51
|
+
const behind = goal.current - from;
|
|
52
|
+
if (behind > 0) {
|
|
53
|
+
const held = arriving * BUFFER_MS / 1e3;
|
|
54
|
+
const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + (behind - held) * 1e3 / CORRECT_MS));
|
|
55
|
+
pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);
|
|
56
|
+
cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + elapsed * pace.current / 1e3);
|
|
57
|
+
if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));
|
|
58
|
+
}
|
|
59
|
+
frame = requestAnimationFrame(step);
|
|
60
|
+
});
|
|
61
|
+
return () => cancelAnimationFrame(frame);
|
|
62
|
+
}, [chasing]);
|
|
63
|
+
if (!chasing) return text;
|
|
64
|
+
return text.slice(0, stops[shown]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { useRevealedText as u };
|
|
68
|
+
//# sourceMappingURL=use-reveal-d77hxHz9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-reveal-d77hxHz9.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":";;AAGA,MAAM,SAAA,GAAY,GAAA;AAGlB,MAAM,UAAA,GAAa,GAAA;AAGnB,MAAM,OAAA,GAAU,GAAA;AAGhB,MAAM,OAAA,GAAU,GAAA;AAGhB,MAAM,OAAA,GAAU,EAAA;AAGhB,MAAM,OAAA,GAAU,EAAA;AAGhB,MAAM,OAAA,GAAU,GAAA;AAShB,SAAS,OAAA,CAAQ,IAAA,EAAY,GAAA,EAAa,MAAA,EAAwB;AAGhE,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAA,GAAM,KAAK,EAAE,CAAA;AACzC,EAAA,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAC,OAAA,GAAU,OAAO,CAAA,GAAI,MAAA,IAAU,OAAA,GAAU,GAAA,CAAA;AAC3E,EAAA,IAAA,CAAK,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,GAAG,CAAA;AAE/B,EAAA,OAAO,IAAA,CAAK,IAAA;AACd;AAEA,SAAS,oBAAA,GAAgC;AACvC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,MAAA,CAAO,YAAY,OAAO,KAAA;AAChE,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,kCAAkC,CAAA,CAAE,OAAA;AAC/D;AAGA,SAAS,UAAU,IAAA,EAAwB;AACzC,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAC,CAAA;AAChB,EAAA,MAAM,IAAA,GAAO,MAAA;AAEb,EAAA,KAAA,IAAS,QAAQ,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,EAAG,KAAA,EAAO,QAAQ,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,QAAS,IAAA,CAAK,KAAA,CAAM,QAAQ,KAAA,CAAM,CAAC,EAAE,MAAM,CAAA;AAE1G,EAAA,OAAO,KAAA;AACT;AA2BO,SAAS,eAAA,CAAgB,MAAc,SAAA,EAA4B;AACxE,EAAA,MAAM,CAAC,IAAI,CAAA,GAAI,QAAA,CAAS,oBAAoB,CAAA;AAC5C,EAAA,MAAM,KAAA,GAAQ,QAAQ,MAAM,SAAA,CAAU,IAAI,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AACnD,EAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,GAAS,CAAA;AAE7B,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAA,CAAS,MAAO,SAAA,IAAa,CAAC,IAAA,GAAO,CAAA,GAAI,KAAM,CAAA;AAI3E,EAAA,MAAM,KAAA,GAAQ,IAAA,GAAO,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,KAAA,GAAQ,OAAO,CAAC,CAAA;AAC9E,EAAA,IAAI,KAAA,KAAU,MAAA,EAAQ,SAAA,CAAU,KAAK,CAAA;AAErC,EAAA,MAAM,UAAU,KAAA,GAAQ,KAAA;AACxB,EAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AACzB,EAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,EAAA,MAAM,OAAO,MAAA,CAAa,EAAE,MAAM,CAAA,EAAG,EAAA,EAAI,GAAG,CAAA;AAC5C,EAAA,MAAM,IAAA,GAAO,OAAO,OAAO,CAAA;AAE3B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,WAAA,CAAY,GAAA,EAAI,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,GAAQ,IAAA,CAAK,OAAO,CAAC,CAAA;AAC1E,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAEf,IAAA,IAAI,OAAO,OAAA,GAAU,KAAA,IAAS,OAAO,OAAA,GAAU,KAAA,SAAc,OAAA,GAAU,KAAA;AAAA,EACzE,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,IAAI,KAAA,GAAQ,YAAY,GAAA,EAAI;AAC5B,IAAA,IAAI,KAAA,GAAQ,qBAAA,CAAsB,SAAS,IAAA,CAAK,GAAA,EAAK;AACnD,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,KAAK,CAAA;AACvC,MAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,GAAG,CAAA;AAE3B,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,KAAK,CAAC,CAAA;AAC7C,MAAA,MAAM,OAAO,MAAA,CAAO,OAAA;AACpB,MAAA,MAAM,MAAA,GAAS,KAAK,OAAA,GAAU,IAAA;AAE9B,MAAA,IAAI,SAAS,CAAA,EAAG;AACd,QAAA,MAAM,IAAA,GAAQ,WAAW,SAAA,GAAa,GAAA;AACtC,QAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,QAAA,GAAA,CAAa,MAAA,GAAS,IAAA,IAAQ,GAAA,GAAQ,UAAU,CAAC,CAAA;AAEjG,QAAA,IAAA,CAAK,OAAA,IAAA,CAAY,MAAM,IAAA,CAAK,OAAA,IAAW,KAAK,GAAA,CAAI,CAAA,EAAG,UAAU,OAAO,CAAA;AACpE,QAAA,MAAA,CAAO,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,SAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,GAAI,CAAA,EAAG,IAAA,GAAQ,OAAA,GAAU,IAAA,CAAK,UAAW,GAAI,CAAA;AAEpG,QAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,OAAO,MAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG,SAAA,CAAU,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,MAC3F;AAEA,MAAA,KAAA,GAAQ,sBAAsB,IAAI,CAAA;AAAA,IACpC,CAAC,CAAA;AAED,IAAA,OAAO,MAAM,qBAAqB,KAAK,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,KAAK,CAAC,CAAA;AACnC;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/* `accent6` is the system orange (the hue behind `warning1`), used at full strength so a
|
|
2
|
+
match stays legible against dense JSON. Only color, background-color, text-decoration
|
|
3
|
+
and text-shadow are honoured by `::highlight()` — border, padding and border-radius are
|
|
4
|
+
ignored by the spec, so the highlight cannot have rounded corners. */
|
|
5
|
+
::highlight(search-result) {
|
|
6
|
+
background-color: var(--color-accent6);
|
|
7
|
+
color: var(--color-surface1);
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/playground-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "51.
|
|
4
|
+
"version": "51.3.0-alpha.1",
|
|
5
5
|
"description": "Mastra Playground components",
|
|
6
6
|
"sideEffects": [
|
|
7
7
|
"**/*.css"
|
|
@@ -161,8 +161,8 @@
|
|
|
161
161
|
"react": ">=19.0.0",
|
|
162
162
|
"react-dom": ">=19.0.0",
|
|
163
163
|
"tailwindcss": "^4.0.0",
|
|
164
|
-
"@mastra/client-js": "^1.42.
|
|
165
|
-
"@mastra/react": "1.4.
|
|
164
|
+
"@mastra/client-js": "^1.42.3-alpha.1",
|
|
165
|
+
"@mastra/react": "1.4.8-alpha.1"
|
|
166
166
|
},
|
|
167
167
|
"devDependencies": {
|
|
168
168
|
"@storybook/addon-a11y": "^10.4.1",
|
|
@@ -202,11 +202,11 @@
|
|
|
202
202
|
"vite-plugin-dts": "^4.5.4",
|
|
203
203
|
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
204
204
|
"vitest": "4.1.10",
|
|
205
|
-
"@mastra/client-js": "^1.42.
|
|
206
|
-
"@
|
|
207
|
-
"@mastra/memory": "1.28.0",
|
|
208
|
-
"@mastra/react": "1.4.
|
|
209
|
-
"@
|
|
205
|
+
"@mastra/client-js": "^1.42.3-alpha.1",
|
|
206
|
+
"@mastra/core": "1.63.1-alpha.1",
|
|
207
|
+
"@mastra/memory": "1.28.1-alpha.0",
|
|
208
|
+
"@mastra/react": "1.4.8-alpha.1",
|
|
209
|
+
"@internal/lint": "0.0.127"
|
|
210
210
|
},
|
|
211
211
|
"homepage": "https://mastra.ai",
|
|
212
212
|
"repository": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-field-block-BqRM53jf.cjs","sources":["../src/ds/components/FormFieldBlocks/fields/search-field-block.tsx"],"sourcesContent":["import { SearchIcon, XIcon } from 'lucide-react';\nimport { useEffect, useRef } from 'react';\nimport { Button } from '../../Button';\nimport { Input } from '../../Input';\nimport type { InputProps } from '../../Input';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../Tooltip';\nimport { FieldBlock } from '../block/field-block';\nimport { cn } from '@/lib/utils';\n\nexport type SearchFieldBlockProps = {\n name: string;\n testId?: string;\n label?: string;\n labelIsHidden?: boolean;\n required?: boolean;\n disabled?: boolean;\n value?: string;\n placeholder?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onReset?: () => void;\n helpText?: string;\n error?: boolean;\n errorMsg?: string;\n layout?: 'horizontal' | 'vertical';\n className?: string;\n size?: InputProps['size'];\n variant?: InputProps['variant'];\n isMinimized?: boolean;\n onMinimizedChange?: (minimized: boolean) => void;\n};\n\nexport function SearchFieldBlock({\n name,\n helpText,\n errorMsg,\n required = false,\n disabled = false,\n value,\n label,\n labelIsHidden = false,\n layout = 'vertical',\n placeholder = 'Search...',\n onChange,\n onReset,\n className,\n size,\n variant,\n isMinimized,\n onMinimizedChange,\n}: SearchFieldBlockProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const buttonSize = size === 'default' ? 'lg' : size;\n\n useEffect(() => {\n if (isMinimized === false) {\n inputRef.current?.focus();\n }\n }, [isMinimized]);\n\n if (isMinimized) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n size={buttonSize || 'sm'}\n aria-label={label || 'Search'}\n disabled={disabled}\n onClick={() => onMinimizedChange?.(false)}\n >\n <SearchIcon />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label || 'Search'}</TooltipContent>\n </Tooltip>\n );\n }\n\n return (\n <FieldBlock.Layout layout={layout} className={className}>\n {layout === 'horizontal' ? (\n <FieldBlock.Column className={labelIsHidden ? 'sr-only' : undefined}>\n <FieldBlock.Label name={name} required={required}>\n {label}\n </FieldBlock.Label>\n </FieldBlock.Column>\n ) : null}\n <FieldBlock.Column className={layout === 'horizontal' && labelIsHidden ? 'col-span-full' : undefined}>\n {layout === 'vertical' && label ? (\n <FieldBlock.Label name={name} required={required} className={labelIsHidden ? 'sr-only' : undefined}>\n {label}\n </FieldBlock.Label>\n ) : null}\n <div className=\"group relative\">\n <Input\n ref={inputRef}\n id={`input-${name}`}\n name={name}\n disabled={disabled}\n value={value}\n placeholder={placeholder}\n onChange={onChange}\n size={size}\n variant={variant}\n className={cn(\n size === 'sm' && 'px-8',\n size === 'md' && 'px-9',\n (!size || size === 'default') && 'px-10',\n size === 'lg' && 'px-11',\n )}\n />\n <SearchIcon\n aria-hidden=\"true\"\n className={cn(\n 'absolute top-1/2 left-3 -translate-y-1/2 text-neutral4 opacity-50 group-has-focus:opacity-100',\n size === 'sm' && 'size-3.5',\n size === 'md' && 'size-4',\n (!size || size === 'default') && 'size-[1.125rem]',\n size === 'lg' && 'size-5',\n )}\n />\n {onReset && (value || isMinimized === false) && (\n <Button\n variant=\"ghost\"\n size={buttonSize || 'lg'}\n aria-label=\"Clear search\"\n onClick={() => {\n if (value) {\n onReset();\n }\n if (isMinimized === false) {\n onMinimizedChange?.(true);\n }\n }}\n className=\"absolute top-1/2 right-0 -translate-y-1/2\"\n >\n <XIcon />\n </Button>\n )}\n </div>\n {helpText && <FieldBlock.HelpText>{helpText}</FieldBlock.HelpText>}\n {errorMsg && <FieldBlock.ErrorMsg>{errorMsg}</FieldBlock.ErrorMsg>}\n </FieldBlock.Column>\n </FieldBlock.Layout>\n );\n}\n"],"names":["useRef","useEffect","Tooltip","jsx","TooltipTrigger","Button","SearchIcon","TooltipContent","jsxs","FieldBlock","Input","cn","XIcon"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-field-block-CgrC6f9t.js","sources":["../src/ds/components/FormFieldBlocks/fields/search-field-block.tsx"],"sourcesContent":["import { SearchIcon, XIcon } from 'lucide-react';\nimport { useEffect, useRef } from 'react';\nimport { Button } from '../../Button';\nimport { Input } from '../../Input';\nimport type { InputProps } from '../../Input';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../Tooltip';\nimport { FieldBlock } from '../block/field-block';\nimport { cn } from '@/lib/utils';\n\nexport type SearchFieldBlockProps = {\n name: string;\n testId?: string;\n label?: string;\n labelIsHidden?: boolean;\n required?: boolean;\n disabled?: boolean;\n value?: string;\n placeholder?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onReset?: () => void;\n helpText?: string;\n error?: boolean;\n errorMsg?: string;\n layout?: 'horizontal' | 'vertical';\n className?: string;\n size?: InputProps['size'];\n variant?: InputProps['variant'];\n isMinimized?: boolean;\n onMinimizedChange?: (minimized: boolean) => void;\n};\n\nexport function SearchFieldBlock({\n name,\n helpText,\n errorMsg,\n required = false,\n disabled = false,\n value,\n label,\n labelIsHidden = false,\n layout = 'vertical',\n placeholder = 'Search...',\n onChange,\n onReset,\n className,\n size,\n variant,\n isMinimized,\n onMinimizedChange,\n}: SearchFieldBlockProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const buttonSize = size === 'default' ? 'lg' : size;\n\n useEffect(() => {\n if (isMinimized === false) {\n inputRef.current?.focus();\n }\n }, [isMinimized]);\n\n if (isMinimized) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n size={buttonSize || 'sm'}\n aria-label={label || 'Search'}\n disabled={disabled}\n onClick={() => onMinimizedChange?.(false)}\n >\n <SearchIcon />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label || 'Search'}</TooltipContent>\n </Tooltip>\n );\n }\n\n return (\n <FieldBlock.Layout layout={layout} className={className}>\n {layout === 'horizontal' ? (\n <FieldBlock.Column className={labelIsHidden ? 'sr-only' : undefined}>\n <FieldBlock.Label name={name} required={required}>\n {label}\n </FieldBlock.Label>\n </FieldBlock.Column>\n ) : null}\n <FieldBlock.Column className={layout === 'horizontal' && labelIsHidden ? 'col-span-full' : undefined}>\n {layout === 'vertical' && label ? (\n <FieldBlock.Label name={name} required={required} className={labelIsHidden ? 'sr-only' : undefined}>\n {label}\n </FieldBlock.Label>\n ) : null}\n <div className=\"group relative\">\n <Input\n ref={inputRef}\n id={`input-${name}`}\n name={name}\n disabled={disabled}\n value={value}\n placeholder={placeholder}\n onChange={onChange}\n size={size}\n variant={variant}\n className={cn(\n size === 'sm' && 'px-8',\n size === 'md' && 'px-9',\n (!size || size === 'default') && 'px-10',\n size === 'lg' && 'px-11',\n )}\n />\n <SearchIcon\n aria-hidden=\"true\"\n className={cn(\n 'absolute top-1/2 left-3 -translate-y-1/2 text-neutral4 opacity-50 group-has-focus:opacity-100',\n size === 'sm' && 'size-3.5',\n size === 'md' && 'size-4',\n (!size || size === 'default') && 'size-[1.125rem]',\n size === 'lg' && 'size-5',\n )}\n />\n {onReset && (value || isMinimized === false) && (\n <Button\n variant=\"ghost\"\n size={buttonSize || 'lg'}\n aria-label=\"Clear search\"\n onClick={() => {\n if (value) {\n onReset();\n }\n if (isMinimized === false) {\n onMinimizedChange?.(true);\n }\n }}\n className=\"absolute top-1/2 right-0 -translate-y-1/2\"\n >\n <XIcon />\n </Button>\n )}\n </div>\n {helpText && <FieldBlock.HelpText>{helpText}</FieldBlock.HelpText>}\n {errorMsg && <FieldBlock.ErrorMsg>{errorMsg}</FieldBlock.ErrorMsg>}\n </FieldBlock.Column>\n </FieldBlock.Layout>\n );\n}\n"],"names":[],"mappings":"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"}
|