@workflow/web-shared 5.0.0-beta.2 → 5.0.0-beta.20
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/dist/components/error-boundary.js +1 -1
- package/dist/components/event-list-view.d.ts +16 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +196 -85
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -1
- package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
- package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +10 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.js +46 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +15 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.js +105 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +36 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +254 -0
- package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +19 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
- package/dist/components/new-trace-viewer/context.d.ts +15 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/context.js +47 -0
- package/dist/components/new-trace-viewer/icons.d.ts +6 -0
- package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/icons.js +15 -0
- package/dist/components/new-trace-viewer/search.d.ts +19 -0
- package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/search.js +134 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +11 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +462 -0
- package/dist/components/new-trace-viewer/types.d.ts +3 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/types.js +2 -0
- package/dist/components/new-trace-viewer/utils.d.ts +61 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +345 -0
- package/dist/components/run-trace-view.js +1 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +129 -102
- package/dist/components/sidebar/attributes-block.d.ts +28 -0
- package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
- package/dist/components/sidebar/attributes-block.js +81 -0
- package/dist/components/sidebar/conversation-view.js +1 -1
- package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
- package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +16 -15
- package/dist/components/sidebar/detail-card.d.ts +5 -6
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +32 -16
- package/dist/components/sidebar/entity-detail-panel.d.ts +1 -3
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +17 -35
- package/dist/components/sidebar/events-list.d.ts +3 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +36 -22
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar-data-context.js +19 -0
- package/dist/components/sidebar/span-detail-merge.d.ts +16 -0
- package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
- package/dist/components/sidebar/span-detail-merge.js +53 -0
- package/dist/components/stream-viewer.d.ts +1 -1
- package/dist/components/stream-viewer.d.ts.map +1 -1
- package/dist/components/stream-viewer.js +3 -27
- package/dist/components/trace-viewer/components/map.js +1 -1
- package/dist/components/trace-viewer/components/markers.js +1 -1
- package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
- package/dist/components/trace-viewer/components/node.js +2 -1
- package/dist/components/trace-viewer/components/search-input.js +1 -1
- package/dist/components/trace-viewer/components/search.js +1 -1
- package/dist/components/trace-viewer/components/span-content.js +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
- package/dist/components/trace-viewer/components/span-segments.js +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js +1 -1
- package/dist/components/trace-viewer/components/ui.js +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
- package/dist/components/trace-viewer/context.js +1 -1
- package/dist/components/trace-viewer/index.js +1 -1
- package/dist/components/trace-viewer/trace-viewer.js +1 -1
- package/dist/components/trace-viewer/trace-viewer.module.css +4 -4
- package/dist/components/trace-viewer/types.js +1 -1
- package/dist/components/trace-viewer/util/constants.js +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts +3 -3
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +8 -11
- package/dist/components/trace-viewer/util/tree.js +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
- package/dist/components/trace-viewer/worker.js +1 -1
- package/dist/components/trace-viewer-new.d.ts +14 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +21 -0
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +46 -0
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/context-card.d.ts +47 -0
- package/dist/components/ui/context-card.d.ts.map +1 -0
- package/dist/components/ui/context-card.js +471 -0
- package/dist/components/ui/data-inspector.d.ts +22 -0
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +103 -13
- package/dist/components/ui/decrypt-button.js +1 -1
- package/dist/components/ui/error-card.js +1 -1
- package/dist/components/ui/error-stack-block.d.ts +17 -10
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +49 -30
- package/dist/components/ui/icon-button.d.ts +19 -0
- package/dist/components/ui/icon-button.d.ts.map +1 -0
- package/dist/components/ui/icon-button.js +29 -0
- package/dist/components/ui/inspector-theme.d.ts +9 -10
- package/dist/components/ui/inspector-theme.d.ts.map +1 -1
- package/dist/components/ui/inspector-theme.js +39 -72
- package/dist/components/ui/kbd.d.ts +6 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +6 -0
- package/dist/components/ui/load-more-button.js +1 -1
- package/dist/components/ui/menu-dropdown.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
- package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
- package/dist/components/ui/timestamp-tooltip.js +80 -132
- package/dist/components/ui/tooltip.d.ts +10 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +12 -0
- package/dist/components/workflow-trace-view.d.ts +1 -3
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +11 -13
- package/dist/components/workflow-traces/event-colors.d.ts +1 -0
- package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
- package/dist/components/workflow-traces/event-colors.js +12 -1
- package/dist/components/workflow-traces/trace-colors.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.d.ts +2 -2
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +19 -5
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-intersection-observer.d.ts +17 -0
- package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
- package/dist/hooks/use-intersection-observer.js +29 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
- package/dist/hooks/use-load-more-on-scroll.js +28 -0
- package/dist/hooks/use-reduced-motion.d.ts +10 -0
- package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
- package/dist/hooks/use-reduced-motion.js +29 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/event-analysis.js +1 -1
- package/dist/lib/event-materialization.js +1 -1
- package/dist/lib/exact-event-search-id.d.ts +25 -0
- package/dist/lib/exact-event-search-id.d.ts.map +1 -0
- package/dist/lib/exact-event-search-id.js +39 -0
- package/dist/lib/hydration.d.ts +6 -0
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +154 -2
- package/dist/lib/stream-display.d.ts +18 -0
- package/dist/lib/stream-display.d.ts.map +1 -0
- package/dist/lib/stream-display.js +30 -0
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.d.ts +15 -0
- package/dist/lib/trace-builder.d.ts.map +1 -1
- package/dist/lib/trace-builder.js +29 -3
- package/dist/lib/utils.d.ts +20 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +74 -31
- package/dist/lib/zstd-browser-decoder.d.ts +7 -0
- package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
- package/dist/lib/zstd-browser-decoder.js +41 -0
- package/dist/styles.css +484 -1
- package/package.json +10 -5
- package/src/components/event-list-view.tsx +279 -104
- package/src/components/index.ts +7 -0
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +136 -0
- package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
- package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
- package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
- package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
- package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +198 -0
- package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +744 -0
- package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +94 -0
- package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
- package/src/components/new-trace-viewer/context.tsx +90 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +843 -0
- package/src/components/new-trace-viewer/types.ts +2 -0
- package/src/components/new-trace-viewer/utils.test.ts +182 -0
- package/src/components/new-trace-viewer/utils.ts +519 -0
- package/src/components/sidebar/attribute-panel.tsx +194 -240
- package/src/components/sidebar/attributes-block.tsx +173 -0
- package/src/components/sidebar/copyable-data-block.tsx +49 -27
- package/src/components/sidebar/detail-card.tsx +119 -59
- package/src/components/sidebar/entity-detail-panel.tsx +55 -111
- package/src/components/sidebar/events-list.tsx +85 -96
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/sidebar/span-detail-merge.ts +65 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer/components/node.tsx +3 -2
- package/src/components/trace-viewer/trace-viewer.module.css +4 -4
- package/src/components/trace-viewer/util/timing.ts +7 -11
- package/src/components/trace-viewer-new.tsx +55 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/context-card.tsx +784 -0
- package/src/components/ui/data-inspector.tsx +244 -22
- package/src/components/ui/error-stack-block.tsx +84 -55
- package/src/components/ui/icon-button.tsx +53 -0
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/ui/kbd.tsx +21 -0
- package/src/components/ui/timestamp-tooltip.tsx +132 -194
- package/src/components/ui/tooltip.tsx +47 -0
- package/src/components/workflow-trace-view.tsx +19 -15
- package/src/components/workflow-traces/event-colors.ts +12 -0
- package/src/components/workflow-traces/trace-span-construction.ts +24 -5
- package/src/hooks/use-intersection-observer.ts +57 -0
- package/src/hooks/use-load-more-on-scroll.ts +49 -0
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/src/index.ts +9 -0
- package/src/lib/exact-event-search-id.ts +67 -0
- package/src/lib/hydration.ts +166 -1
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/trace-builder.ts +34 -2
- package/src/lib/utils.ts +83 -31
- package/src/lib/zstd-browser-decoder.ts +42 -0
- package/src/styles.css +484 -1
- package/dist/components/error-boundary.js.map +0 -1
- package/dist/components/event-list-view.js.map +0 -1
- package/dist/components/hook-actions.js.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/components/run-trace-view.js.map +0 -1
- package/dist/components/sidebar/attribute-panel.js.map +0 -1
- package/dist/components/sidebar/conversation-view.js.map +0 -1
- package/dist/components/sidebar/copyable-data-block.js.map +0 -1
- package/dist/components/sidebar/detail-card.js.map +0 -1
- package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/components/sidebar/events-list.js.map +0 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/components/stream-viewer.js.map +0 -1
- package/dist/components/trace-viewer/components/map.js.map +0 -1
- package/dist/components/trace-viewer/components/markers.js.map +0 -1
- package/dist/components/trace-viewer/components/node.js.map +0 -1
- package/dist/components/trace-viewer/components/search-input.js.map +0 -1
- package/dist/components/trace-viewer/components/search.js.map +0 -1
- package/dist/components/trace-viewer/components/span-content.js.map +0 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
- package/dist/components/trace-viewer/components/ui.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/components/trace-viewer/context.js.map +0 -1
- package/dist/components/trace-viewer/index.js.map +0 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/trace-viewer/types.js.map +0 -1
- package/dist/components/trace-viewer/util/constants.js.map +0 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/components/trace-viewer/util/timing.js.map +0 -1
- package/dist/components/trace-viewer/util/tree.js.map +0 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/components/trace-viewer/worker.js.map +0 -1
- package/dist/components/ui/alert.js.map +0 -1
- package/dist/components/ui/card.js.map +0 -1
- package/dist/components/ui/data-inspector.js.map +0 -1
- package/dist/components/ui/decrypt-button.js.map +0 -1
- package/dist/components/ui/error-card.js.map +0 -1
- package/dist/components/ui/error-stack-block.js.map +0 -1
- package/dist/components/ui/inspector-theme.js.map +0 -1
- package/dist/components/ui/load-more-button.js.map +0 -1
- package/dist/components/ui/menu-dropdown.js.map +0 -1
- package/dist/components/ui/skeleton.js.map +0 -1
- package/dist/components/ui/spinner.js.map +0 -1
- package/dist/components/ui/timestamp-tooltip.js.map +0 -1
- package/dist/components/workflow-trace-view.js.map +0 -1
- package/dist/components/workflow-traces/event-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
- package/dist/hooks/use-dark-mode.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/event-analysis.js.map +0 -1
- package/dist/lib/event-materialization.js.map +0 -1
- package/dist/lib/hydration.js.map +0 -1
- package/dist/lib/toast.js.map +0 -1
- package/dist/lib/trace-builder.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
|
@@ -26,6 +26,11 @@ import {
|
|
|
26
26
|
} from 'react-inspector';
|
|
27
27
|
import { useDarkMode } from '../../hooks/use-dark-mode';
|
|
28
28
|
import { ENCRYPTED_DISPLAY_NAME } from '../../lib/hydration';
|
|
29
|
+
import {
|
|
30
|
+
type DecodedStreamChunkSource,
|
|
31
|
+
type FormattedStreamChunkDisplay,
|
|
32
|
+
formatArrayBufferViewForDisplay,
|
|
33
|
+
} from '../../lib/stream-display';
|
|
29
34
|
import {
|
|
30
35
|
type InspectorThemeExtended,
|
|
31
36
|
inspectorThemeDark,
|
|
@@ -33,6 +38,7 @@ import {
|
|
|
33
38
|
inspectorThemeExtendedLight,
|
|
34
39
|
inspectorThemeLight,
|
|
35
40
|
} from './inspector-theme';
|
|
41
|
+
import { Button } from './button';
|
|
36
42
|
import { Spinner } from './spinner';
|
|
37
43
|
|
|
38
44
|
// ---------------------------------------------------------------------------
|
|
@@ -43,6 +49,7 @@ import { Spinner } from './spinner';
|
|
|
43
49
|
const STREAM_REF_TYPE = '__workflow_stream_ref__';
|
|
44
50
|
const CLASS_INSTANCE_REF_TYPE = '__workflow_class_instance_ref__';
|
|
45
51
|
const RUN_REF_TYPE = '__workflow_run_ref__';
|
|
52
|
+
const BYTES_DISPLAY_TYPE = '__workflow_bytes_display__';
|
|
46
53
|
|
|
47
54
|
interface StreamRef {
|
|
48
55
|
__type: typeof STREAM_REF_TYPE;
|
|
@@ -54,6 +61,32 @@ interface RunRef {
|
|
|
54
61
|
runId: string;
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
interface BytesDisplay {
|
|
65
|
+
__type: typeof BYTES_DISPLAY_TYPE;
|
|
66
|
+
text: string;
|
|
67
|
+
decodedFrom?: DecodedStreamChunkSource;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function deserializeChunkText(text: string): string {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(text);
|
|
73
|
+
if (typeof parsed === 'string') {
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
return JSON.stringify(parsed, null, 2);
|
|
77
|
+
} catch {
|
|
78
|
+
return text;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function parseChunkData(text: string): unknown {
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(text);
|
|
85
|
+
} catch {
|
|
86
|
+
return text;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
57
90
|
function isStreamRef(value: unknown): value is StreamRef {
|
|
58
91
|
if (value === null || typeof value !== 'object') return false;
|
|
59
92
|
// Check both enumerable and non-enumerable __type (opaque refs use non-enumerable)
|
|
@@ -67,6 +100,12 @@ function isRunRef(value: unknown): value is RunRef {
|
|
|
67
100
|
return desc?.value === RUN_REF_TYPE;
|
|
68
101
|
}
|
|
69
102
|
|
|
103
|
+
export function isBytesDisplay(value: unknown): value is BytesDisplay {
|
|
104
|
+
if (value === null || typeof value !== 'object') return false;
|
|
105
|
+
const desc = Object.getOwnPropertyDescriptor(value, '__type');
|
|
106
|
+
return desc?.value === BYTES_DISPLAY_TYPE;
|
|
107
|
+
}
|
|
108
|
+
|
|
70
109
|
function isClassInstanceRef(value: unknown): value is {
|
|
71
110
|
__type: string;
|
|
72
111
|
className: string;
|
|
@@ -100,6 +139,7 @@ export const StreamClickContext = createContext<
|
|
|
100
139
|
export type DecryptClickContextValue = {
|
|
101
140
|
onDecrypt: () => void;
|
|
102
141
|
isDecrypting: boolean;
|
|
142
|
+
hasEncryptedData?: boolean;
|
|
103
143
|
};
|
|
104
144
|
|
|
105
145
|
export const DecryptClickContext = createContext<
|
|
@@ -114,33 +154,22 @@ function EncryptedInlineLabel() {
|
|
|
114
154
|
const ctx = useContext(DecryptClickContext);
|
|
115
155
|
if (ctx) {
|
|
116
156
|
return (
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
className="
|
|
120
|
-
style={{
|
|
121
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
122
|
-
color: 'var(--ds-gray-700)',
|
|
123
|
-
border: '1px solid var(--ds-gray-400)',
|
|
124
|
-
fontStyle: 'italic',
|
|
125
|
-
opacity: ctx.isDecrypting ? 0.6 : 1,
|
|
126
|
-
}}
|
|
157
|
+
<Button
|
|
158
|
+
size="xs"
|
|
159
|
+
className="align-baseline gap-x-1"
|
|
127
160
|
disabled={ctx.isDecrypting}
|
|
128
161
|
onClick={(e) => {
|
|
129
162
|
e.stopPropagation();
|
|
130
163
|
ctx.onDecrypt();
|
|
131
164
|
}}
|
|
132
|
-
title="Click to decrypt"
|
|
133
165
|
>
|
|
134
166
|
{ctx.isDecrypting ? (
|
|
135
|
-
<Spinner size={
|
|
167
|
+
<Spinner size={10} />
|
|
136
168
|
) : (
|
|
137
|
-
<Lock
|
|
138
|
-
className="h-3 w-3"
|
|
139
|
-
style={{ display: 'inline', flexShrink: 0 }}
|
|
140
|
-
/>
|
|
169
|
+
<Lock className="h-3 w-3" />
|
|
141
170
|
)}
|
|
142
|
-
<span>
|
|
143
|
-
</
|
|
171
|
+
<span>Decrypt</span>
|
|
172
|
+
</Button>
|
|
144
173
|
);
|
|
145
174
|
}
|
|
146
175
|
return (
|
|
@@ -219,6 +248,147 @@ const ExtendedThemeContext = createContext<InspectorThemeExtended>(
|
|
|
219
248
|
inspectorThemeExtendedLight
|
|
220
249
|
);
|
|
221
250
|
|
|
251
|
+
function DecodedBytesChunk({
|
|
252
|
+
decodedText,
|
|
253
|
+
source,
|
|
254
|
+
}: {
|
|
255
|
+
decodedText: string;
|
|
256
|
+
source: DecodedStreamChunkSource;
|
|
257
|
+
}) {
|
|
258
|
+
const [selectedView, setSelectedView] = useState<'decoded' | 'bytes'>(
|
|
259
|
+
'decoded'
|
|
260
|
+
);
|
|
261
|
+
const parsed = parseChunkData(decodedText);
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<div className="min-w-0">
|
|
265
|
+
{selectedView === 'decoded' ? (
|
|
266
|
+
<div className="min-w-0">
|
|
267
|
+
{typeof parsed === 'string' ? (
|
|
268
|
+
<span
|
|
269
|
+
className="whitespace-pre-wrap break-words"
|
|
270
|
+
style={{ color: 'var(--ds-gray-1000)' }}
|
|
271
|
+
>
|
|
272
|
+
{deserializeChunkText(parsed)}
|
|
273
|
+
</span>
|
|
274
|
+
) : (
|
|
275
|
+
<DataInspector data={parsed} expandLevel={1} />
|
|
276
|
+
)}
|
|
277
|
+
</div>
|
|
278
|
+
) : (
|
|
279
|
+
<DecodedBytesInspector decodedText={decodedText} source={source} />
|
|
280
|
+
)}
|
|
281
|
+
<div className="mt-2 flex">
|
|
282
|
+
<div
|
|
283
|
+
className="inline-flex overflow-hidden rounded border"
|
|
284
|
+
style={{ borderColor: 'var(--ds-gray-400)' }}
|
|
285
|
+
title={`${source.type} decoded as ${source.encoding.toUpperCase()} text. Switch to Bytes to inspect the summarized raw value.`}
|
|
286
|
+
>
|
|
287
|
+
<button
|
|
288
|
+
type="button"
|
|
289
|
+
className="h-5 px-1.5 text-[10px] font-medium"
|
|
290
|
+
style={{
|
|
291
|
+
backgroundColor:
|
|
292
|
+
selectedView === 'decoded'
|
|
293
|
+
? 'var(--ds-gray-200)'
|
|
294
|
+
: 'var(--ds-gray-100)',
|
|
295
|
+
color: 'var(--ds-gray-900)',
|
|
296
|
+
}}
|
|
297
|
+
onClick={() => setSelectedView('decoded')}
|
|
298
|
+
aria-pressed={selectedView === 'decoded'}
|
|
299
|
+
aria-label="Show decoded text"
|
|
300
|
+
>
|
|
301
|
+
Decoded
|
|
302
|
+
</button>
|
|
303
|
+
<button
|
|
304
|
+
type="button"
|
|
305
|
+
className="h-5 border-l px-1.5 text-[10px] font-medium"
|
|
306
|
+
style={{
|
|
307
|
+
borderColor: 'var(--ds-gray-400)',
|
|
308
|
+
backgroundColor:
|
|
309
|
+
selectedView === 'bytes'
|
|
310
|
+
? 'var(--ds-gray-200)'
|
|
311
|
+
: 'var(--ds-gray-100)',
|
|
312
|
+
color: 'var(--ds-gray-900)',
|
|
313
|
+
}}
|
|
314
|
+
onClick={() => setSelectedView('bytes')}
|
|
315
|
+
aria-pressed={selectedView === 'bytes'}
|
|
316
|
+
aria-label="Show raw bytes summary"
|
|
317
|
+
>
|
|
318
|
+
Bytes
|
|
319
|
+
</button>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
</div>
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function DecodedBytesInspector({
|
|
327
|
+
decodedText,
|
|
328
|
+
source,
|
|
329
|
+
}: {
|
|
330
|
+
decodedText: string;
|
|
331
|
+
source: DecodedStreamChunkSource;
|
|
332
|
+
}) {
|
|
333
|
+
const [expanded, setExpanded] = useState(false);
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
<div className="font-mono">
|
|
337
|
+
<button
|
|
338
|
+
type="button"
|
|
339
|
+
className="flex max-w-full items-start gap-1 text-left"
|
|
340
|
+
style={{ color: 'var(--ds-gray-1000)' }}
|
|
341
|
+
onClick={() => setExpanded((value) => !value)}
|
|
342
|
+
title={`${source.type} decoded as ${source.encoding.toUpperCase()} text`}
|
|
343
|
+
>
|
|
344
|
+
<span className="select-none" style={{ color: 'var(--ds-gray-700)' }}>
|
|
345
|
+
{expanded ? '▼' : '▶'}
|
|
346
|
+
</span>
|
|
347
|
+
<span className="min-w-0 break-words">{source.rawSummary}</span>
|
|
348
|
+
</button>
|
|
349
|
+
{expanded && (
|
|
350
|
+
<div className="mt-1 pl-5">
|
|
351
|
+
<span style={{ color: 'var(--ds-gray-700)' }}>decoded: </span>
|
|
352
|
+
<span
|
|
353
|
+
className="whitespace-pre-wrap break-words"
|
|
354
|
+
style={{ color: 'var(--ds-green-900)' }}
|
|
355
|
+
>
|
|
356
|
+
{JSON.stringify(decodedText)}
|
|
357
|
+
</span>
|
|
358
|
+
</div>
|
|
359
|
+
)}
|
|
360
|
+
</div>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function BytesDisplayLabel({
|
|
365
|
+
name,
|
|
366
|
+
display,
|
|
367
|
+
}: {
|
|
368
|
+
name?: string;
|
|
369
|
+
display: BytesDisplay;
|
|
370
|
+
}) {
|
|
371
|
+
return (
|
|
372
|
+
<div className="inline-block min-w-0 align-top">
|
|
373
|
+
{name != null && <ObjectName name={name} />}
|
|
374
|
+
{name != null && <span>: </span>}
|
|
375
|
+
{display.decodedFrom ? (
|
|
376
|
+
<DecodedBytesChunk
|
|
377
|
+
decodedText={display.text}
|
|
378
|
+
source={display.decodedFrom}
|
|
379
|
+
/>
|
|
380
|
+
) : (
|
|
381
|
+
<span
|
|
382
|
+
className="whitespace-pre-wrap break-words"
|
|
383
|
+
style={{ color: 'var(--ds-gray-1000)' }}
|
|
384
|
+
>
|
|
385
|
+
{display.text}
|
|
386
|
+
</span>
|
|
387
|
+
)}
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
222
392
|
// ---------------------------------------------------------------------------
|
|
223
393
|
// Custom nodeRenderer
|
|
224
394
|
// ---------------------------------------------------------------------------
|
|
@@ -248,6 +418,10 @@ function NodeRenderer({
|
|
|
248
418
|
}) {
|
|
249
419
|
const extendedTheme = useContext(ExtendedThemeContext);
|
|
250
420
|
|
|
421
|
+
if (isBytesDisplay(data)) {
|
|
422
|
+
return <BytesDisplayLabel name={name} display={data} />;
|
|
423
|
+
}
|
|
424
|
+
|
|
251
425
|
// Encrypted marker → flat label with Lock icon, clickable when onDecrypt is available
|
|
252
426
|
if (
|
|
253
427
|
data !== null &&
|
|
@@ -352,18 +526,53 @@ function makeOpaqueRef(ref: Record<string, unknown>): unknown {
|
|
|
352
526
|
return opaque;
|
|
353
527
|
}
|
|
354
528
|
|
|
529
|
+
function makeBytesDisplay(display: FormattedStreamChunkDisplay): unknown {
|
|
530
|
+
const opaque = Object.create(null);
|
|
531
|
+
Object.defineProperty(opaque, '__type', {
|
|
532
|
+
value: BYTES_DISPLAY_TYPE,
|
|
533
|
+
enumerable: false,
|
|
534
|
+
});
|
|
535
|
+
Object.defineProperty(opaque, 'text', {
|
|
536
|
+
value: display.text,
|
|
537
|
+
enumerable: false,
|
|
538
|
+
});
|
|
539
|
+
Object.defineProperty(opaque, 'decodedFrom', {
|
|
540
|
+
value: display.decodedFrom,
|
|
541
|
+
enumerable: false,
|
|
542
|
+
});
|
|
543
|
+
return opaque;
|
|
544
|
+
}
|
|
545
|
+
|
|
355
546
|
/**
|
|
356
|
-
* Recursively walk data and replace RunRef/StreamRef objects with
|
|
547
|
+
* Recursively walk data and replace RunRef/StreamRef/typed array objects with
|
|
357
548
|
* non-expandable versions so ObjectInspector doesn't show their internals.
|
|
358
549
|
* Only recurses into plain objects and arrays to avoid stripping class
|
|
359
|
-
* instances (Date, Error,
|
|
360
|
-
*
|
|
550
|
+
* instances (Date, Error, URL, Headers, etc.) that have their own rendering in
|
|
551
|
+
* NodeRenderer. Map and Set containers are preserved while their contents are
|
|
552
|
+
* prepared for display.
|
|
553
|
+
*
|
|
554
|
+
* Exported for testing the typed-array detection path used by hydrated
|
|
555
|
+
* AI agent stream chunks (e.g. `{ delta: new Uint8Array(...) }`).
|
|
361
556
|
*/
|
|
362
|
-
function collapseRefs(data: unknown): unknown {
|
|
557
|
+
export function collapseRefs(data: unknown): unknown {
|
|
363
558
|
if (data === null || typeof data !== 'object') return data;
|
|
559
|
+
if (ArrayBuffer.isView(data) && !(data instanceof DataView)) {
|
|
560
|
+
return makeBytesDisplay(formatArrayBufferViewForDisplay(data));
|
|
561
|
+
}
|
|
364
562
|
if (isRunRef(data) || isStreamRef(data))
|
|
365
563
|
return makeOpaqueRef(data as unknown as Record<string, unknown>);
|
|
366
564
|
if (Array.isArray(data)) return data.map(collapseRefs);
|
|
565
|
+
if (data instanceof Map) {
|
|
566
|
+
return new Map(
|
|
567
|
+
Array.from(data.entries(), ([key, value]) => [
|
|
568
|
+
collapseRefs(key),
|
|
569
|
+
collapseRefs(value),
|
|
570
|
+
])
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
if (data instanceof Set) {
|
|
574
|
+
return new Set(Array.from(data.values(), collapseRefs));
|
|
575
|
+
}
|
|
367
576
|
// Only recurse into plain objects — leave class instances untouched
|
|
368
577
|
const proto = Object.getPrototypeOf(data);
|
|
369
578
|
if (proto !== Object.prototype && proto !== null) return data;
|
|
@@ -467,9 +676,22 @@ function isObjectLike(value: unknown): value is Record<string, unknown> {
|
|
|
467
676
|
return typeof value === 'object' && value !== null;
|
|
468
677
|
}
|
|
469
678
|
|
|
679
|
+
function isSameBytesDisplay(a: BytesDisplay, b: BytesDisplay): boolean {
|
|
680
|
+
return (
|
|
681
|
+
a.text === b.text &&
|
|
682
|
+
a.decodedFrom?.type === b.decodedFrom?.type &&
|
|
683
|
+
a.decodedFrom?.encoding === b.decodedFrom?.encoding &&
|
|
684
|
+
a.decodedFrom?.rawSummary === b.decodedFrom?.rawSummary
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
470
688
|
function isDeepEqual(a: unknown, b: unknown, seen = new WeakMap()): boolean {
|
|
471
689
|
if (Object.is(a, b)) return true;
|
|
472
690
|
|
|
691
|
+
if (isBytesDisplay(a) || isBytesDisplay(b)) {
|
|
692
|
+
return isBytesDisplay(a) && isBytesDisplay(b) && isSameBytesDisplay(a, b);
|
|
693
|
+
}
|
|
694
|
+
|
|
473
695
|
if (a instanceof Date && b instanceof Date) {
|
|
474
696
|
return a.getTime() === b.getTime();
|
|
475
697
|
}
|
|
@@ -1,37 +1,73 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { AlertCircle
|
|
4
|
-
import {
|
|
3
|
+
import { AlertCircle } from 'lucide-react';
|
|
4
|
+
import { CopyButton } from '../new-trace-viewer/components/copy-button';
|
|
5
|
+
|
|
6
|
+
export type StructuredErrorRecord = Record<string, unknown> & {
|
|
7
|
+
message?: string;
|
|
8
|
+
stack?: string;
|
|
9
|
+
};
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
|
-
* Check whether `value` looks like a structured error object
|
|
8
|
-
*
|
|
12
|
+
* Check whether `value` looks like a structured error object we can render
|
|
13
|
+
* with the error block. Some persisted workflow errors only include a
|
|
14
|
+
* `message`, while runtime errors usually also include `stack`.
|
|
9
15
|
*/
|
|
10
|
-
export function
|
|
16
|
+
export function isStructuredError(
|
|
11
17
|
value: unknown
|
|
12
|
-
): value is
|
|
18
|
+
): value is StructuredErrorRecord {
|
|
13
19
|
return (
|
|
14
20
|
value != null &&
|
|
15
21
|
typeof value === 'object' &&
|
|
16
|
-
'
|
|
17
|
-
|
|
22
|
+
(typeof (value as Record<string, unknown>).message === 'string' ||
|
|
23
|
+
typeof (value as Record<string, unknown>).stack === 'string')
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Narrower guard kept for callers that specifically need a stack trace.
|
|
29
|
+
*/
|
|
30
|
+
export function isStructuredErrorWithStack(
|
|
31
|
+
value: unknown
|
|
32
|
+
): value is StructuredErrorRecord & { stack: string } {
|
|
33
|
+
return (
|
|
34
|
+
isStructuredError(value) &&
|
|
35
|
+
typeof (value as StructuredErrorRecord).stack === 'string'
|
|
18
36
|
);
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* the
|
|
40
|
+
* Pull a short, single-line title out of an error message.
|
|
41
|
+
*
|
|
42
|
+
* Workflow's structured error messages are multi-line — the first line is
|
|
43
|
+
* the headline (`Failed to serialize step return value`) and the rest are
|
|
44
|
+
* `╰▶ hint:` / `╰▶ docs:` framed details. The full message belongs in the
|
|
45
|
+
* body of the error block; the title should just be the headline so the
|
|
46
|
+
* card stays scannable.
|
|
25
47
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
48
|
+
function deriveTitle(message: string): string {
|
|
49
|
+
const firstLine =
|
|
50
|
+
message.split('\n').find((line) => line.trim().length > 0) ?? message;
|
|
51
|
+
return firstLine.trim();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Renders a structured error as a visually distinct error block. Shows the
|
|
56
|
+
* error message with an alert icon at the top, separated from the stack trace
|
|
57
|
+
* or full message below.
|
|
58
|
+
*/
|
|
59
|
+
export function ErrorStackBlock({ value }: { value: StructuredErrorRecord }) {
|
|
60
|
+
const stack = typeof value.stack === 'string' ? value.stack : undefined;
|
|
33
61
|
const message = typeof value.message === 'string' ? value.message : undefined;
|
|
34
|
-
const
|
|
62
|
+
const body = stack ?? message ?? '';
|
|
63
|
+
// V8's `Error.stack` already starts with `Name: message`; message-only
|
|
64
|
+
// errors use the message as the body so long single-line failures remain
|
|
65
|
+
// readable even when the header truncates.
|
|
66
|
+
const title = message ? deriveTitle(message) : deriveTitle(body);
|
|
67
|
+
const copyText =
|
|
68
|
+
message && stack && !stack.includes(message)
|
|
69
|
+
? `${message}\n\n${stack}`
|
|
70
|
+
: body;
|
|
35
71
|
|
|
36
72
|
return (
|
|
37
73
|
<div
|
|
@@ -41,51 +77,44 @@ export function ErrorStackBlock({
|
|
|
41
77
|
background: 'var(--ds-red-100)',
|
|
42
78
|
}}
|
|
43
79
|
>
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
style={{
|
|
50
|
-
borderColor: 'var(--ds-red-400)',
|
|
51
|
-
background: 'var(--ds-red-100)',
|
|
52
|
-
color: 'var(--ds-red-900)',
|
|
53
|
-
}}
|
|
54
|
-
onClick={() => {
|
|
55
|
-
navigator.clipboard
|
|
56
|
-
.writeText(copyText)
|
|
57
|
-
.then(() => {
|
|
58
|
-
toast.success('Copied to clipboard');
|
|
59
|
-
})
|
|
60
|
-
.catch(() => {
|
|
61
|
-
toast.error('Failed to copy');
|
|
62
|
-
});
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
<Copy size={12} />
|
|
66
|
-
</button>
|
|
80
|
+
<CopyButton
|
|
81
|
+
copyText={copyText}
|
|
82
|
+
ariaLabel="Copy error"
|
|
83
|
+
className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-md border border-red-400 bg-red-100 p-0 text-red-900 transition-transform transition-colors duration-100 hover:bg-red-200 active:scale-95"
|
|
84
|
+
/>
|
|
67
85
|
|
|
68
|
-
{
|
|
86
|
+
{title && (
|
|
69
87
|
<div
|
|
70
|
-
className="flex items-
|
|
88
|
+
className="flex items-center gap-2 px-3 py-2.5 pr-10"
|
|
71
89
|
style={{
|
|
72
90
|
color: 'var(--ds-red-900)',
|
|
73
91
|
borderBottom: '1px solid var(--ds-red-400)',
|
|
74
92
|
}}
|
|
75
93
|
>
|
|
76
|
-
<AlertCircle className="h-4 w-4 shrink-0"
|
|
77
|
-
<p
|
|
94
|
+
<AlertCircle className="h-4 w-4 shrink-0" />
|
|
95
|
+
<p
|
|
96
|
+
className="text-xs font-semibold m-0 truncate"
|
|
97
|
+
// The full message or stack is in the body below; the header just
|
|
98
|
+
// shows the first line, single-line, with overflow
|
|
99
|
+
// ellipsised so a long title doesn't push the copy button or
|
|
100
|
+
// wrap into the framed hint/docs lines.
|
|
101
|
+
title={message}
|
|
102
|
+
>
|
|
103
|
+
{title}
|
|
104
|
+
</p>
|
|
78
105
|
</div>
|
|
79
106
|
)}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
{body && (
|
|
108
|
+
<pre
|
|
109
|
+
className="px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0"
|
|
110
|
+
style={{
|
|
111
|
+
color: 'var(--ds-red-900)',
|
|
112
|
+
background: 'var(--ds-red-200)',
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{body}
|
|
116
|
+
</pre>
|
|
117
|
+
)}
|
|
89
118
|
</div>
|
|
90
119
|
);
|
|
91
120
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const iconButtonVariants = cva(
|
|
6
|
+
[
|
|
7
|
+
'm-0 inline-flex shrink-0 appearance-none items-center justify-center border-0 bg-transparent p-0 align-baseline font-inherit no-underline [background:none] [-webkit-appearance:none] [-webkit-tap-highlight-color:transparent]',
|
|
8
|
+
'transition-colors duration-150 ease-in-out',
|
|
9
|
+
'enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-40',
|
|
10
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] focus-visible:outline-offset-2',
|
|
11
|
+
],
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
tertiary:
|
|
16
|
+
'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
|
|
17
|
+
muted:
|
|
18
|
+
'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
tiny: 'h-6 w-6 rounded-[4px] [&_svg]:h-4 [&_svg]:w-4',
|
|
22
|
+
small: 'h-8 w-8 rounded-md [&_svg]:h-4 [&_svg]:w-4',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: 'tertiary',
|
|
27
|
+
size: 'tiny',
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export type IconButtonProps = Omit<
|
|
33
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
34
|
+
'type'
|
|
35
|
+
> &
|
|
36
|
+
VariantProps<typeof iconButtonVariants> & {
|
|
37
|
+
'aria-label': string;
|
|
38
|
+
type?: 'button' | 'submit' | 'reset';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
42
|
+
({ className, variant, size, type = 'button', ...props }, ref) => (
|
|
43
|
+
<button
|
|
44
|
+
ref={ref}
|
|
45
|
+
type={type}
|
|
46
|
+
className={cn(iconButtonVariants({ variant, size, className }))}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
IconButton.displayName = 'IconButton';
|
|
52
|
+
|
|
53
|
+
export { iconButtonVariants };
|