@runtypelabs/persona 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animations/glyph-cycle.cjs +2 -2
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/glyph-cycle.js +2 -2
- package/dist/animations/{types-CSmiKRVa.d.cts → types-BsZtXPKK.d.cts} +43 -3
- package/dist/animations/{types-CSmiKRVa.d.ts → types-BsZtXPKK.d.ts} +43 -3
- package/dist/animations/wipe.cjs +2 -2
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/chunk-5EIIHQLQ.js +1 -0
- package/dist/codegen.cjs +12 -12
- package/dist/codegen.js +14 -14
- package/dist/index.cjs +91 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +877 -172
- package/dist/index.d.ts +877 -172
- package/dist/index.global.js +81 -57
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +91 -68
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +3 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/markdown-parsers.js +24 -24
- package/dist/plugin-kit.cjs +1 -1
- package/dist/plugin-kit.js +1 -1
- package/dist/runtype-tts-entry-UJAEF7NZ.js +1 -0
- package/dist/runtype-tts.js +1 -1
- package/dist/session-reconnect-JKIJBHS5.js +1 -0
- package/dist/smart-dom-reader.cjs +17 -17
- package/dist/smart-dom-reader.d.cts +753 -15
- package/dist/smart-dom-reader.d.ts +753 -15
- package/dist/smart-dom-reader.js +17 -17
- package/dist/testing.cjs +3 -3
- package/dist/testing.js +3 -3
- package/dist/theme-editor-preview.cjs +81 -58
- package/dist/theme-editor-preview.d.cts +761 -15
- package/dist/theme-editor-preview.d.ts +761 -15
- package/dist/theme-editor-preview.js +81 -58
- package/dist/theme-editor.cjs +6 -6
- package/dist/theme-editor.d.cts +753 -15
- package/dist/theme-editor.d.ts +753 -15
- package/dist/theme-editor.js +10 -10
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +74 -0
- package/dist/theme-reference.d.ts +74 -0
- package/dist/theme-reference.js +1 -1
- package/dist/voice-worklet-player.cjs +2 -2
- package/dist/voice-worklet-player.js +2 -2
- package/dist/webmcp-polyfill.js +2 -2
- package/dist/widget.css +1 -1
- package/package.json +2 -3
- package/src/artifacts-session.test.ts +178 -0
- package/src/client.test.ts +186 -1
- package/src/client.ts +92 -9
- package/src/components/artifact-card.test.ts +333 -0
- package/src/components/artifact-card.ts +75 -28
- package/src/components/artifact-inline.test.ts +1328 -0
- package/src/components/artifact-inline.ts +920 -0
- package/src/components/artifact-pane.test.ts +1042 -0
- package/src/components/artifact-pane.ts +440 -131
- package/src/components/artifact-preview.test.ts +1155 -0
- package/src/components/artifact-preview.ts +994 -0
- package/src/components/pill-composer-builder.test.ts +6 -2
- package/src/components/pill-composer-builder.ts +6 -6
- package/src/components/reasoning-bubble.ts +1 -13
- package/src/components/registry.ts +38 -3
- package/src/components/tool-bubble.ts +1 -13
- package/src/defaults.ts +1 -0
- package/src/generated/runtype-openapi-contract.ts +55 -3
- package/src/index-core.ts +20 -1
- package/src/index.ts +8 -0
- package/src/markdown-parsers-loader.test.ts +158 -0
- package/src/markdown-parsers-loader.ts +74 -9
- package/src/runtime/host-layout.test.ts +163 -0
- package/src/runtime/host-layout.ts +110 -7
- package/src/runtime/init.ts +18 -61
- package/src/session.ts +76 -22
- package/src/styles/widget.css +773 -26
- package/src/theme-editor/preview.ts +2 -0
- package/src/theme-editor/sections.test.ts +26 -1
- package/src/theme-editor/sections.ts +10 -2
- package/src/theme-reference.ts +2 -2
- package/src/tool-call-display-defaults.test.ts +1 -0
- package/src/types/theme.ts +77 -0
- package/src/types.ts +516 -17
- package/src/ui.artifact-pane-gating.test.ts +636 -0
- package/src/ui.component-directive.test.ts +104 -0
- package/src/ui.composer-bar.test.ts +60 -2
- package/src/ui.detached-panel.test.ts +1049 -0
- package/src/ui.tool-display.test.ts +51 -0
- package/src/ui.ts +698 -109
- package/src/utils/artifact-custom-actions.ts +128 -0
- package/src/utils/artifact-display.test.ts +42 -0
- package/src/utils/artifact-display.ts +84 -0
- package/src/utils/artifact-file.test.ts +116 -0
- package/src/utils/artifact-file.ts +117 -0
- package/src/utils/artifact-gate.test.ts +112 -5
- package/src/utils/artifact-gate.ts +39 -14
- package/src/utils/artifact-loading-status.ts +55 -0
- package/src/utils/artifact-status-label.ts +190 -0
- package/src/utils/buttons.ts +7 -1
- package/src/utils/code-highlight.test.ts +186 -0
- package/src/utils/code-highlight.ts +400 -0
- package/src/utils/icons.ts +2 -0
- package/src/utils/roving-tablist.test.ts +152 -0
- package/src/utils/roving-tablist.ts +111 -0
- package/src/utils/spinner.ts +45 -0
- package/src/utils/theme.test.ts +48 -0
- package/src/utils/theme.ts +7 -0
- package/src/utils/tokens.ts +91 -0
- package/src/utils/tool-loading-animation.test.ts +32 -0
- package/src/utils/tool-loading-animation.ts +24 -0
- package/dist/chunk-DFBSCFYN.js +0 -1
- package/dist/runtype-tts-entry-HFUV2UF7.js +0 -1
- package/dist/session-reconnect-U77QFUR7.js +0 -1
package/src/styles/widget.css
CHANGED
|
@@ -725,6 +725,10 @@
|
|
|
725
725
|
flex-shrink: 0;
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
+
.persona-shrink-0 {
|
|
729
|
+
flex-shrink: 0;
|
|
730
|
+
}
|
|
731
|
+
|
|
728
732
|
.persona-min-w-0 {
|
|
729
733
|
min-width: 0;
|
|
730
734
|
}
|
|
@@ -863,6 +867,10 @@
|
|
|
863
867
|
overflow-y: auto;
|
|
864
868
|
}
|
|
865
869
|
|
|
870
|
+
.persona-overflow-x-auto {
|
|
871
|
+
overflow-x: auto;
|
|
872
|
+
}
|
|
873
|
+
|
|
866
874
|
.persona-widget-body {
|
|
867
875
|
overscroll-behavior: contain;
|
|
868
876
|
}
|
|
@@ -2668,7 +2676,12 @@
|
|
|
2668
2676
|
}
|
|
2669
2677
|
|
|
2670
2678
|
/* Document toolbar preset: optional layout vars: --persona-artifact-doc-toolbar-icon-color, etc. */
|
|
2671
|
-
|
|
2679
|
+
/* Document-toolbar icon/copy button styling is shared by the artifact pane's
|
|
2680
|
+
document preset and the inline chrome actions cluster, so both surfaces read
|
|
2681
|
+
the same `components.artifact.toolbar` tokens (the vars are emitted globally
|
|
2682
|
+
at the widget root). */
|
|
2683
|
+
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn,
|
|
2684
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions .persona-artifact-doc-icon-btn {
|
|
2672
2685
|
display: inline-flex;
|
|
2673
2686
|
align-items: center;
|
|
2674
2687
|
justify-content: center;
|
|
@@ -2681,17 +2694,20 @@
|
|
|
2681
2694
|
line-height: 1;
|
|
2682
2695
|
}
|
|
2683
2696
|
|
|
2684
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn:hover
|
|
2697
|
+
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn:hover,
|
|
2698
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions .persona-artifact-doc-icon-btn:hover {
|
|
2685
2699
|
color: var(--persona-artifact-toolbar-icon-hover-color, inherit);
|
|
2686
|
-
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-container, #f3f4f6));
|
|
2700
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-icon-btn-hover-bg, var(--persona-container, #f3f4f6)));
|
|
2687
2701
|
}
|
|
2688
2702
|
|
|
2689
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn[aria-pressed="true"]
|
|
2690
|
-
|
|
2691
|
-
|
|
2703
|
+
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn[aria-pressed="true"],
|
|
2704
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions .persona-artifact-doc-icon-btn[aria-pressed="true"] {
|
|
2705
|
+
background: var(--persona-artifact-doc-toggle-active-bg, var(--persona-icon-btn-active-bg, var(--persona-container, #f3f4f6)));
|
|
2706
|
+
border-color: var(--persona-artifact-doc-toggle-active-border, var(--persona-icon-btn-active-border, var(--persona-border, #e5e7eb)));
|
|
2692
2707
|
}
|
|
2693
2708
|
|
|
2694
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn
|
|
2709
|
+
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn,
|
|
2710
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions .persona-artifact-doc-copy-btn {
|
|
2695
2711
|
display: inline-flex;
|
|
2696
2712
|
align-items: center;
|
|
2697
2713
|
gap: 0.35rem;
|
|
@@ -2705,8 +2721,9 @@
|
|
|
2705
2721
|
line-height: 1.25;
|
|
2706
2722
|
}
|
|
2707
2723
|
|
|
2708
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn:hover
|
|
2709
|
-
|
|
2724
|
+
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn:hover,
|
|
2725
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions .persona-artifact-doc-copy-btn:hover {
|
|
2726
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-icon-btn-hover-bg, var(--persona-container, #f3f4f6)));
|
|
2710
2727
|
}
|
|
2711
2728
|
|
|
2712
2729
|
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-label {
|
|
@@ -2718,6 +2735,12 @@
|
|
|
2718
2735
|
background: var(--persona-artifact-tab-bg, transparent);
|
|
2719
2736
|
border-radius: var(--persona-artifact-tab-radius, 0.5rem);
|
|
2720
2737
|
color: var(--persona-artifact-tab-color, inherit);
|
|
2738
|
+
/* Keep each tab on one line and cap its width so the strip scrolls
|
|
2739
|
+
horizontally instead of wrapping/overflowing the pane. */
|
|
2740
|
+
white-space: nowrap;
|
|
2741
|
+
max-width: var(--persona-artifact-tab-max-width, 12rem);
|
|
2742
|
+
overflow: hidden;
|
|
2743
|
+
text-overflow: ellipsis;
|
|
2721
2744
|
}
|
|
2722
2745
|
|
|
2723
2746
|
[data-persona-root] .persona-artifact-tab.persona-bg-persona-container {
|
|
@@ -2730,27 +2753,40 @@
|
|
|
2730
2753
|
background: var(--persona-artifact-toolbar-bg, var(--persona-surface, #fff));
|
|
2731
2754
|
}
|
|
2732
2755
|
|
|
2733
|
-
/* Toggle group
|
|
2734
|
-
|
|
2735
|
-
gap: var(--persona-artifact-toolbar-toggle-group-gap, 0.25rem);
|
|
2736
|
-
}
|
|
2737
|
-
|
|
2738
|
-
/* Toggle button border-radius (view/code buttons) */
|
|
2739
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-view-btn,
|
|
2740
|
-
[data-persona-root] .persona-artifact-toolbar-document .persona-artifact-code-btn {
|
|
2741
|
-
border-radius: var(--persona-artifact-toolbar-toggle-radius, var(--persona-artifact-toolbar-icon-radius, var(--persona-radius-md, 0.375rem)));
|
|
2742
|
-
}
|
|
2756
|
+
/* Toggle group + view/code button styling lives in the segmented
|
|
2757
|
+
.persona-toggle-group.persona-artifact-toggle-group block further down. */
|
|
2743
2758
|
|
|
2744
2759
|
/* Tab hover */
|
|
2745
2760
|
[data-persona-root] .persona-artifact-tab:hover {
|
|
2746
2761
|
background: var(--persona-artifact-tab-hover-bg, var(--persona-container, #f3f4f6));
|
|
2747
2762
|
}
|
|
2748
2763
|
|
|
2764
|
+
/* Keyboard focus ring, themed to match cards/buttons instead of the UA default
|
|
2765
|
+
(which varies by browser). Custom renderTabBar bars reuse .persona-artifact-tab,
|
|
2766
|
+
so they inherit the same ring; give a scroll container enough padding that the
|
|
2767
|
+
2px offset isn't clipped. */
|
|
2768
|
+
[data-persona-root] .persona-artifact-tab:focus-visible {
|
|
2769
|
+
outline: 2px solid var(--persona-accent, #171717);
|
|
2770
|
+
outline-offset: 2px;
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2749
2773
|
/* Tab list container */
|
|
2750
2774
|
[data-persona-root] .persona-artifact-list {
|
|
2751
2775
|
background: var(--persona-artifact-tab-list-bg, transparent);
|
|
2752
2776
|
border-bottom-color: var(--persona-artifact-tab-list-border-color, var(--persona-border, #e5e7eb));
|
|
2753
2777
|
padding: var(--persona-artifact-tab-list-padding, 0.5rem);
|
|
2778
|
+
/* Thin, unobtrusive horizontal scrollbar for the tab strip. */
|
|
2779
|
+
scrollbar-width: thin;
|
|
2780
|
+
scroll-behavior: smooth;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
[data-persona-root] .persona-artifact-list::-webkit-scrollbar {
|
|
2784
|
+
height: 6px;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
[data-persona-root] .persona-artifact-list::-webkit-scrollbar-thumb {
|
|
2788
|
+
background: var(--persona-artifact-tab-list-scrollbar, var(--persona-border, #e5e7eb));
|
|
2789
|
+
border-radius: 9999px;
|
|
2754
2790
|
}
|
|
2755
2791
|
|
|
2756
2792
|
/* Toolbar border override */
|
|
@@ -2758,6 +2794,23 @@
|
|
|
2758
2794
|
border-bottom: var(--persona-artifact-toolbar-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2759
2795
|
}
|
|
2760
2796
|
|
|
2797
|
+
/* Artifact reference card (chat thread) */
|
|
2798
|
+
[data-persona-root] .persona-artifact-card {
|
|
2799
|
+
background: var(--persona-artifact-card-bg, var(--persona-surface, #ffffff));
|
|
2800
|
+
border: var(--persona-artifact-card-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2801
|
+
border-radius: var(--persona-artifact-card-radius, var(--persona-message-assistant-radius, var(--persona-radius-lg, 0.5rem)));
|
|
2802
|
+
cursor: pointer;
|
|
2803
|
+
transition: background-color 0.15s ease, border-color 0.15s ease;
|
|
2804
|
+
}
|
|
2805
|
+
[data-persona-root] .persona-artifact-card:hover {
|
|
2806
|
+
background: var(--persona-artifact-card-hover-bg, #f3f4f6);
|
|
2807
|
+
border-color: var(--persona-artifact-card-hover-border, var(--persona-border, #e5e7eb));
|
|
2808
|
+
}
|
|
2809
|
+
[data-persona-root] .persona-artifact-card:focus-visible {
|
|
2810
|
+
outline: 2px solid var(--persona-accent, #171717);
|
|
2811
|
+
outline-offset: 2px;
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2761
2814
|
/* ── Composable button utilities ── */
|
|
2762
2815
|
|
|
2763
2816
|
/* Icon button: base for all icon-only buttons created by createIconButton() */
|
|
@@ -2929,6 +2982,89 @@
|
|
|
2929
2982
|
border-bottom-right-radius: var(--persona-toggle-group-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem)));
|
|
2930
2983
|
}
|
|
2931
2984
|
|
|
2985
|
+
/* Artifact view/source toggle: one segmented pill. The container carries the
|
|
2986
|
+
border; segments are borderless and the active one is highlighted, so the
|
|
2987
|
+
pair reads as a single mutually exclusive switch instead of two buttons. */
|
|
2988
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group {
|
|
2989
|
+
gap: var(--persona-artifact-toolbar-toggle-group-gap, 2px);
|
|
2990
|
+
padding: var(--persona-artifact-toolbar-toggle-group-padding, 2px);
|
|
2991
|
+
border: var(--persona-artifact-toolbar-toggle-group-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2992
|
+
/* Default to the toolbar button radius (document preset var, then the plain
|
|
2993
|
+
icon-button var) so the pill matches the neighboring copy/close buttons
|
|
2994
|
+
instead of standing out as a capsule. */
|
|
2995
|
+
border-radius: var(--persona-artifact-toolbar-toggle-group-radius, var(--persona-artifact-toolbar-icon-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem))));
|
|
2996
|
+
background: var(--persona-artifact-toolbar-toggle-group-bg, var(--persona-surface, #ffffff));
|
|
2997
|
+
}
|
|
2998
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group > .persona-icon-btn {
|
|
2999
|
+
border: none;
|
|
3000
|
+
background: transparent;
|
|
3001
|
+
/* Segment padding = standalone icon-button padding minus the container's
|
|
3002
|
+
padding, so the pill's outer height matches the neighboring icon buttons
|
|
3003
|
+
(the container's 1px border stands in for the border the segments lost).
|
|
3004
|
+
calc() clamps to 0 if a theme sets group padding larger than icon padding. */
|
|
3005
|
+
padding: calc(var(--persona-artifact-toolbar-icon-padding, var(--persona-icon-btn-padding, 0.25rem)) - var(--persona-artifact-toolbar-toggle-group-padding, 2px));
|
|
3006
|
+
/* Container radius minus the 2px padding so the segment nests concentrically. */
|
|
3007
|
+
border-radius: var(--persona-artifact-toolbar-toggle-radius, calc(var(--persona-artifact-toolbar-icon-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem))) - 2px));
|
|
3008
|
+
}
|
|
3009
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group > .persona-icon-btn:hover {
|
|
3010
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-icon-btn-hover-bg, var(--persona-container, #f3f4f6)));
|
|
3011
|
+
}
|
|
3012
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group > .persona-icon-btn[aria-pressed="true"] {
|
|
3013
|
+
background: var(--persona-artifact-doc-toggle-active-bg, var(--persona-icon-btn-active-bg, var(--persona-container, #f3f4f6)));
|
|
3014
|
+
/* Inset ring instead of a border so documentToolbarToggleActiveBorderColor
|
|
3015
|
+
still applies inside the borderless segment (transparent by default). */
|
|
3016
|
+
box-shadow: inset 0 0 0 1px var(--persona-artifact-doc-toggle-active-border, transparent);
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
/* Sliding selection thumb: a container ::before that translates between the
|
|
3020
|
+
two equal-width segments, keyed off aria-pressed via :has(). The static
|
|
3021
|
+
aria-pressed background above stays as the fallback for browsers without
|
|
3022
|
+
:has() and is disabled inside the @supports block so the highlight is only
|
|
3023
|
+
ever painted once. Geometry assumes the group's two segments are equal
|
|
3024
|
+
width (both are square icon buttons). */
|
|
3025
|
+
@supports selector(:has(*)) {
|
|
3026
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group {
|
|
3027
|
+
position: relative;
|
|
3028
|
+
}
|
|
3029
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group::before {
|
|
3030
|
+
content: "";
|
|
3031
|
+
position: absolute;
|
|
3032
|
+
top: var(--persona-artifact-toolbar-toggle-group-padding, 2px);
|
|
3033
|
+
bottom: var(--persona-artifact-toolbar-toggle-group-padding, 2px);
|
|
3034
|
+
left: var(--persona-artifact-toolbar-toggle-group-padding, 2px);
|
|
3035
|
+
width: calc(
|
|
3036
|
+
50% - var(--persona-artifact-toolbar-toggle-group-padding, 2px) -
|
|
3037
|
+
(var(--persona-artifact-toolbar-toggle-group-gap, 2px) / 2)
|
|
3038
|
+
);
|
|
3039
|
+
border-radius: var(--persona-artifact-toolbar-toggle-radius, calc(var(--persona-artifact-toolbar-icon-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem))) - 2px));
|
|
3040
|
+
background: var(--persona-artifact-doc-toggle-active-bg, var(--persona-icon-btn-active-bg, var(--persona-container, #f3f4f6)));
|
|
3041
|
+
box-shadow: inset 0 0 0 1px var(--persona-artifact-doc-toggle-active-border, transparent);
|
|
3042
|
+
transition: transform 0.18s ease;
|
|
3043
|
+
pointer-events: none;
|
|
3044
|
+
}
|
|
3045
|
+
[data-persona-root]
|
|
3046
|
+
.persona-toggle-group.persona-artifact-toggle-group:has(
|
|
3047
|
+
> .persona-icon-btn:last-child[aria-pressed="true"]
|
|
3048
|
+
)::before {
|
|
3049
|
+
transform: translateX(calc(100% + var(--persona-artifact-toolbar-toggle-group-gap, 2px)));
|
|
3050
|
+
}
|
|
3051
|
+
/* Positioned so the segments paint above the absolutely positioned thumb
|
|
3052
|
+
(document order applies once both are in the positioned layer). */
|
|
3053
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group > .persona-icon-btn {
|
|
3054
|
+
position: relative;
|
|
3055
|
+
}
|
|
3056
|
+
/* The thumb carries the highlight; keep the segment itself transparent. */
|
|
3057
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group > .persona-icon-btn[aria-pressed="true"] {
|
|
3058
|
+
background: transparent;
|
|
3059
|
+
box-shadow: none;
|
|
3060
|
+
}
|
|
3061
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3062
|
+
[data-persona-root] .persona-toggle-group.persona-artifact-toggle-group::before {
|
|
3063
|
+
transition: none;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
|
|
2932
3068
|
/* Combo button: label + chevron with dropdown */
|
|
2933
3069
|
[data-persona-root] .persona-combo-btn {
|
|
2934
3070
|
font-size: var(--persona-combo-btn-font-size, 0.8125rem);
|
|
@@ -3019,11 +3155,560 @@
|
|
|
3019
3155
|
max-width: var(--persona-artifact-pane-max-width, 28rem);
|
|
3020
3156
|
min-width: var(--persona-artifact-pane-min-width, 0);
|
|
3021
3157
|
flex-shrink: 0;
|
|
3022
|
-
|
|
3158
|
+
/* No default elevation on the pane; welded reads as one card, detached and
|
|
3159
|
+
the drawer set their own shadow. Explicit paneShadow still wins. */
|
|
3160
|
+
box-shadow: var(--persona-artifact-pane-shadow, none);
|
|
3023
3161
|
}
|
|
3024
3162
|
}
|
|
3025
3163
|
|
|
3164
|
+
/* Expanded artifact pane: pane takes the whole split root, chat column hides.
|
|
3165
|
+
Split-view only: below 641px / narrow hosts the drawer already covers everything. */
|
|
3166
|
+
@media (min-width: 641px) {
|
|
3167
|
+
[data-persona-root].persona-artifact-expanded .persona-artifact-split-root > :first-child {
|
|
3168
|
+
display: none;
|
|
3169
|
+
}
|
|
3170
|
+
[data-persona-root].persona-artifact-expanded .persona-artifact-pane {
|
|
3171
|
+
width: 100%;
|
|
3172
|
+
max-width: none;
|
|
3173
|
+
}
|
|
3174
|
+
[data-persona-root].persona-artifact-expanded .persona-artifact-split-handle {
|
|
3175
|
+
display: none !important;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
@media (max-width: 640px) {
|
|
3179
|
+
[data-persona-root] .persona-artifact-expand-btn {
|
|
3180
|
+
display: none !important;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
[data-persona-root].persona-artifact-narrow-host .persona-artifact-expand-btn {
|
|
3184
|
+
display: none !important;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3026
3187
|
/* paneBorderRadius: works on any paneAppearance; overflow clips content to rounded shape */
|
|
3188
|
+
/* Positioned frame wrapping the sandboxed preview iframe (artifact-preview.ts).
|
|
3189
|
+
`position: relative` gives the absolute loading overlay a containing block
|
|
3190
|
+
(the shared preview body is display: contents, so the iframe alone has no
|
|
3191
|
+
positioning context). The frame owns the rendered height and the iframe is
|
|
3192
|
+
100% of it — see the pane default here and the inline overrides below.
|
|
3193
|
+
|
|
3194
|
+
Opaque-canvas / color-scheme trap: an opaque-origin srcdoc (sandbox without
|
|
3195
|
+
allow-same-origin) that declares no color-scheme can get a UA-forced opaque
|
|
3196
|
+
canvas that flashes before content paints. Declaring color-scheme on the
|
|
3197
|
+
iframe plus an explicit background on both the frame and iframe makes the
|
|
3198
|
+
pre-paint surface a deliberate, themeable canvas rather than an uncontrolled
|
|
3199
|
+
flash. Artifact content generally assumes a light canvas, so white stays the
|
|
3200
|
+
default; override via --persona-artifact-frame-bg. */
|
|
3201
|
+
[data-persona-root] .persona-artifact-frame {
|
|
3202
|
+
position: relative;
|
|
3203
|
+
width: 100%;
|
|
3204
|
+
height: 100%;
|
|
3205
|
+
background: var(--persona-artifact-frame-bg, #ffffff);
|
|
3206
|
+
}
|
|
3207
|
+
/* Previewable file artifact: sandboxed iframe fills its frame. */
|
|
3208
|
+
[data-persona-root] .persona-artifact-iframe {
|
|
3209
|
+
display: block;
|
|
3210
|
+
width: 100%;
|
|
3211
|
+
height: 100%;
|
|
3212
|
+
border: 0;
|
|
3213
|
+
color-scheme: light;
|
|
3214
|
+
background: var(--persona-artifact-frame-bg, #ffffff);
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
/* Loading overlay above the preview iframe (artifact-preview.ts): absolutely
|
|
3218
|
+
fills the frame with the same themed canvas the iframe paints onto, so the
|
|
3219
|
+
pre-paint area reads as one deliberate surface. Appended only after
|
|
3220
|
+
`loading.delayMs`; the --out modifier fades it before removal. */
|
|
3221
|
+
[data-persona-root] .persona-artifact-frame-loading {
|
|
3222
|
+
position: absolute;
|
|
3223
|
+
inset: 0;
|
|
3224
|
+
display: flex;
|
|
3225
|
+
align-items: center;
|
|
3226
|
+
justify-content: center;
|
|
3227
|
+
background: var(--persona-artifact-frame-bg, #ffffff);
|
|
3228
|
+
opacity: 1;
|
|
3229
|
+
transition: opacity var(--persona-artifact-frame-loading-fade, 200ms) ease;
|
|
3230
|
+
}
|
|
3231
|
+
[data-persona-root] .persona-artifact-frame-loading--out {
|
|
3232
|
+
opacity: 0;
|
|
3233
|
+
}
|
|
3234
|
+
/* Default indicator column: the icon spinner, with the escalation label (when
|
|
3235
|
+
present) stacked below it. Icon-first, text only as a later escalation. */
|
|
3236
|
+
[data-persona-root] .persona-artifact-frame-loading-indicator {
|
|
3237
|
+
display: flex;
|
|
3238
|
+
flex-direction: column;
|
|
3239
|
+
align-items: center;
|
|
3240
|
+
gap: 0.625rem;
|
|
3241
|
+
}
|
|
3242
|
+
/* Escalation label: calm, muted, small — NO shimmer (deliberate, per research).
|
|
3243
|
+
Hidden until setupPreviewLoading adds --visible after labelDelayMs; a plain
|
|
3244
|
+
opacity transition fades it in. */
|
|
3245
|
+
[data-persona-root] .persona-artifact-frame-loading-text {
|
|
3246
|
+
color: var(
|
|
3247
|
+
--persona-artifact-frame-loading-color,
|
|
3248
|
+
var(--persona-text-muted, #6b7280)
|
|
3249
|
+
);
|
|
3250
|
+
font-size: 0.8125rem;
|
|
3251
|
+
font-weight: 500;
|
|
3252
|
+
opacity: 0;
|
|
3253
|
+
transition: opacity 240ms ease;
|
|
3254
|
+
}
|
|
3255
|
+
[data-persona-root] .persona-artifact-frame-loading-text--visible {
|
|
3256
|
+
opacity: 1;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
/* Reusable icon spinner (utils/spinner.ts): a faint full track ring with a
|
|
3260
|
+
rotating arc on top. Icon-first loading is the norm across preview surfaces
|
|
3261
|
+
(Sandpack, embeds, v0/ChatGPT) and design systems (HIG/Material/Carbon/Geist);
|
|
3262
|
+
text-only "loading" is used by none. The arc spins via a GPU-friendly
|
|
3263
|
+
`transform: rotate` keyframe. Fallback chains:
|
|
3264
|
+
- size: --persona-artifact-spinner-size (default 28px)
|
|
3265
|
+
- arc: --persona-artifact-spinner-color → --persona-accent → --persona-primary
|
|
3266
|
+
→ neutral dark (the interactive/brand hue)
|
|
3267
|
+
- track: --persona-artifact-spinner-track-color → --persona-border → light gray
|
|
3268
|
+
- speed: --persona-artifact-spinner-speed (default 0.8s) */
|
|
3269
|
+
[data-persona-root] .persona-spinner {
|
|
3270
|
+
width: var(--persona-artifact-spinner-size, 28px);
|
|
3271
|
+
height: var(--persona-artifact-spinner-size, 28px);
|
|
3272
|
+
transform-origin: center;
|
|
3273
|
+
animation: persona-spinner-rotate var(--persona-artifact-spinner-speed, 0.8s)
|
|
3274
|
+
linear infinite;
|
|
3275
|
+
}
|
|
3276
|
+
[data-persona-root] .persona-spinner-track {
|
|
3277
|
+
fill: none;
|
|
3278
|
+
stroke: var(
|
|
3279
|
+
--persona-artifact-spinner-track-color,
|
|
3280
|
+
var(--persona-border, #e5e7eb)
|
|
3281
|
+
);
|
|
3282
|
+
stroke-width: 2.5;
|
|
3283
|
+
}
|
|
3284
|
+
[data-persona-root] .persona-spinner-arc {
|
|
3285
|
+
fill: none;
|
|
3286
|
+
stroke: var(
|
|
3287
|
+
--persona-artifact-spinner-color,
|
|
3288
|
+
var(--persona-accent, var(--persona-primary, #171717))
|
|
3289
|
+
);
|
|
3290
|
+
stroke-width: 2.5;
|
|
3291
|
+
stroke-linecap: round;
|
|
3292
|
+
/* r=9 → circumference ≈ 56.5; ~15u arc reads as a quarter-ish sweep. */
|
|
3293
|
+
stroke-dasharray: 15 42;
|
|
3294
|
+
}
|
|
3295
|
+
@keyframes persona-spinner-rotate {
|
|
3296
|
+
from {
|
|
3297
|
+
transform: rotate(0deg);
|
|
3298
|
+
}
|
|
3299
|
+
to {
|
|
3300
|
+
transform: rotate(360deg);
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
/* Reduced motion: stop the rotation (the static arc still reads as a ring) and
|
|
3304
|
+
drop the label fade. */
|
|
3305
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3306
|
+
[data-persona-root] .persona-spinner {
|
|
3307
|
+
animation: none;
|
|
3308
|
+
}
|
|
3309
|
+
[data-persona-root] .persona-artifact-frame-loading-text {
|
|
3310
|
+
transition: none;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
/* Shared artifact preview body wrapper (artifact-preview.ts): generates no box
|
|
3315
|
+
so children (e.g. the iframe's height: 100%) lay out against the host
|
|
3316
|
+
container exactly as if they were its direct children. */
|
|
3317
|
+
[data-persona-root] .persona-artifact-preview-body {
|
|
3318
|
+
display: contents;
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
/* Syntax-highlighted source view (code-highlight.ts). The host <pre> keeps its
|
|
3322
|
+
wrapping (persona-whitespace-pre-wrap); <code> resets white-space to normal so
|
|
3323
|
+
the literal "\n" separator text nodes between block line spans collapse
|
|
3324
|
+
visually while still reconstructing the verbatim source via textContent. Each
|
|
3325
|
+
line reserves a left gutter whose number is drawn by a CSS counter — never
|
|
3326
|
+
real text, so it is not selectable or copyable. */
|
|
3327
|
+
/* The source view sits directly on the pane surface (transparent, matching
|
|
3328
|
+
Claude's code view); set --persona-code-bg via theme.components.code.background
|
|
3329
|
+
to render it as an inset sheet instead. */
|
|
3330
|
+
[data-persona-root] .persona-code-pre {
|
|
3331
|
+
margin: 0;
|
|
3332
|
+
background: var(--persona-code-bg, transparent);
|
|
3333
|
+
border-radius: var(--persona-radius-md, 0.375rem);
|
|
3334
|
+
padding: 0.5rem 0.75rem 0.5rem 0.25rem;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
/* Pane source view is full-bleed: the pane drops its content padding (class
|
|
3338
|
+
toggled in artifact-pane.ts when the body rendered a code pre) so the
|
|
3339
|
+
line-number gutter sits flush against the pane's left edge. */
|
|
3340
|
+
[data-persona-root] .persona-artifact-content-flush {
|
|
3341
|
+
padding: 0;
|
|
3342
|
+
}
|
|
3343
|
+
[data-persona-root] .persona-artifact-content-flush .persona-code-pre {
|
|
3344
|
+
padding: 0.5rem 0.75rem 0.5rem 0;
|
|
3345
|
+
border-radius: 0;
|
|
3346
|
+
min-height: 100%;
|
|
3347
|
+
}
|
|
3348
|
+
[data-persona-root] .persona-code {
|
|
3349
|
+
display: block;
|
|
3350
|
+
white-space: normal;
|
|
3351
|
+
counter-reset: persona-code-line;
|
|
3352
|
+
/* Defend against host-page element rules (`code { background/padding/… }`):
|
|
3353
|
+
without Shadow DOM those selectors reach into the widget, and inline-code
|
|
3354
|
+
chip styling on a full source view reads as a mystery tinted block. */
|
|
3355
|
+
background: transparent;
|
|
3356
|
+
padding: 0;
|
|
3357
|
+
border-radius: 0;
|
|
3358
|
+
font-family: inherit;
|
|
3359
|
+
font-size: inherit;
|
|
3360
|
+
color: inherit;
|
|
3361
|
+
}
|
|
3362
|
+
[data-persona-root] .persona-code-line {
|
|
3363
|
+
display: block;
|
|
3364
|
+
position: relative;
|
|
3365
|
+
white-space: pre-wrap;
|
|
3366
|
+
padding-left: 3em;
|
|
3367
|
+
counter-increment: persona-code-line;
|
|
3368
|
+
/* An empty source line emits a childless span — a zero-height block whose
|
|
3369
|
+
absolutely-positioned gutter number would paint on top of the next line's.
|
|
3370
|
+
Reserve one line box (1lh; 1em as the older-engine fallback). */
|
|
3371
|
+
min-height: 1em;
|
|
3372
|
+
min-height: 1lh;
|
|
3373
|
+
}
|
|
3374
|
+
[data-persona-root] .persona-code-line::before {
|
|
3375
|
+
content: counter(persona-code-line);
|
|
3376
|
+
position: absolute;
|
|
3377
|
+
top: 0;
|
|
3378
|
+
left: 0;
|
|
3379
|
+
width: 2em;
|
|
3380
|
+
padding-right: 0.5em;
|
|
3381
|
+
text-align: right;
|
|
3382
|
+
color: var(--persona-code-line-number-color, #a0a1a7);
|
|
3383
|
+
border-right: 1px solid
|
|
3384
|
+
var(--persona-code-gutter-border-color, var(--persona-border, #e5e7eb));
|
|
3385
|
+
-webkit-user-select: none;
|
|
3386
|
+
user-select: none;
|
|
3387
|
+
}
|
|
3388
|
+
/* Default syntax palette: One Light (Atom), the same theme Claude.ai's code
|
|
3389
|
+
view uses. Numbers and attribute names share One's constant orange; CSS
|
|
3390
|
+
properties / JSON keys take the function blue so keys stay distinct from
|
|
3391
|
+
string values. */
|
|
3392
|
+
[data-persona-root] .persona-code-token-keyword {
|
|
3393
|
+
color: var(--persona-code-keyword-color, #a626a4);
|
|
3394
|
+
}
|
|
3395
|
+
[data-persona-root] .persona-code-token-string {
|
|
3396
|
+
color: var(--persona-code-string-color, #50a14f);
|
|
3397
|
+
}
|
|
3398
|
+
[data-persona-root] .persona-code-token-comment {
|
|
3399
|
+
color: var(--persona-code-comment-color, #a0a1a7);
|
|
3400
|
+
font-style: italic;
|
|
3401
|
+
}
|
|
3402
|
+
[data-persona-root] .persona-code-token-number {
|
|
3403
|
+
color: var(--persona-code-number-color, #986801);
|
|
3404
|
+
}
|
|
3405
|
+
[data-persona-root] .persona-code-token-tag {
|
|
3406
|
+
color: var(--persona-code-tag-color, #e45649);
|
|
3407
|
+
}
|
|
3408
|
+
[data-persona-root] .persona-code-token-attr {
|
|
3409
|
+
color: var(--persona-code-attr-color, #986801);
|
|
3410
|
+
}
|
|
3411
|
+
[data-persona-root] .persona-code-token-property {
|
|
3412
|
+
color: var(--persona-code-property-color, #4078f2);
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3415
|
+
/* Dark-scheme defaults for the syntax palette (One Dark counterparts of the
|
|
3416
|
+
One Light defaults above). Keyed off the widget's resolved scheme, stamped
|
|
3417
|
+
as data-persona-color-scheme by applyThemeVariables — NOT the OS
|
|
3418
|
+
prefers-color-scheme, which diverges whenever a host pins colorScheme.
|
|
3419
|
+
The widget's semantic vars can't drive these (syntax colors aren't
|
|
3420
|
+
derivable from surface/text). Explicit theme.components.code values still
|
|
3421
|
+
win in both schemes. */
|
|
3422
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-line::before {
|
|
3423
|
+
color: var(--persona-code-line-number-color, #4b5263);
|
|
3424
|
+
border-right-color: var(--persona-code-gutter-border-color, #3b4048);
|
|
3425
|
+
}
|
|
3426
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-keyword {
|
|
3427
|
+
color: var(--persona-code-keyword-color, #c678dd);
|
|
3428
|
+
}
|
|
3429
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-string {
|
|
3430
|
+
color: var(--persona-code-string-color, #98c379);
|
|
3431
|
+
}
|
|
3432
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-comment {
|
|
3433
|
+
color: var(--persona-code-comment-color, #5c6370);
|
|
3434
|
+
}
|
|
3435
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-number {
|
|
3436
|
+
color: var(--persona-code-number-color, #d19a66);
|
|
3437
|
+
}
|
|
3438
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-tag {
|
|
3439
|
+
color: var(--persona-code-tag-color, #e06c75);
|
|
3440
|
+
}
|
|
3441
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-attr {
|
|
3442
|
+
color: var(--persona-code-attr-color, #d19a66);
|
|
3443
|
+
}
|
|
3444
|
+
[data-persona-root][data-persona-color-scheme="dark"] .persona-code-token-property {
|
|
3445
|
+
color: var(--persona-code-property-color, #61afef);
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
/* Inline artifact block (artifact-inline.ts, display: "inline"): carries its
|
|
3449
|
+
own border/surface (registered with bubbleChrome: false, like the card).
|
|
3450
|
+
Reads like a file preview: a flush title/toolbar chrome bar above the body.
|
|
3451
|
+
Default vars draw from the same semantic surface/border/text/muted family
|
|
3452
|
+
the card uses, so light/dark themes work with zero config. */
|
|
3453
|
+
[data-persona-root] .persona-artifact-inline {
|
|
3454
|
+
border: var(--persona-artifact-inline-border, 1px solid var(--persona-border, #e5e7eb));
|
|
3455
|
+
border-radius: var(
|
|
3456
|
+
--persona-artifact-inline-radius,
|
|
3457
|
+
var(--persona-message-assistant-radius, var(--persona-radius-lg, 0.5rem))
|
|
3458
|
+
);
|
|
3459
|
+
background: var(--persona-artifact-inline-bg, var(--persona-surface, #ffffff));
|
|
3460
|
+
overflow: hidden;
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
/* completeDisplay: "card" — once the block collapses to the compact reference
|
|
3464
|
+
card it keeps the same root (updater keying + theme zone survive) but must
|
|
3465
|
+
drop the inline frame styling, since the nested card carries its own border,
|
|
3466
|
+
background, and radius. overflow: visible so the card's focus outline (which
|
|
3467
|
+
uses outline-offset) isn't clipped. */
|
|
3468
|
+
[data-persona-root] .persona-artifact-inline.persona-artifact-inline--card {
|
|
3469
|
+
border: none;
|
|
3470
|
+
background: transparent;
|
|
3471
|
+
border-radius: 0;
|
|
3472
|
+
overflow: visible;
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
/* Title/toolbar chrome bar: flush to the frame edge (no frame padding). */
|
|
3476
|
+
[data-persona-root] .persona-artifact-inline-chrome {
|
|
3477
|
+
display: flex;
|
|
3478
|
+
align-items: center;
|
|
3479
|
+
gap: 0.5rem;
|
|
3480
|
+
padding: 0.5rem 0.75rem;
|
|
3481
|
+
background: var(--persona-artifact-inline-chrome-bg, var(--persona-surface, #ffffff));
|
|
3482
|
+
border-bottom: 1px solid var(--persona-artifact-inline-chrome-border, var(--persona-border, #e5e7eb));
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
/* Leading cluster: file icon + title + type label / streaming status. */
|
|
3486
|
+
[data-persona-root] .persona-artifact-inline-chrome-lead {
|
|
3487
|
+
display: flex;
|
|
3488
|
+
align-items: center;
|
|
3489
|
+
gap: 0.5rem;
|
|
3490
|
+
min-width: 0;
|
|
3491
|
+
flex: 1 1 auto;
|
|
3492
|
+
color: var(--persona-artifact-inline-title-color, var(--persona-text, #111827));
|
|
3493
|
+
font-size: 0.8125rem;
|
|
3494
|
+
font-weight: 500;
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
[data-persona-root] .persona-artifact-inline-chrome-lead .persona-artifact-inline-type,
|
|
3498
|
+
[data-persona-root] .persona-artifact-inline-chrome-lead .persona-artifact-inline-status {
|
|
3499
|
+
color: var(--persona-artifact-inline-muted-color, var(--persona-text-muted, #6b7280));
|
|
3500
|
+
font-weight: 400;
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3503
|
+
/* Streaming status: animated label span + optional plain detail span (live
|
|
3504
|
+
counters). The label carries the loading animation; the detail updates freely
|
|
3505
|
+
per delta and stays un-animated. Shared by the card, the inline chrome, and
|
|
3506
|
+
the inline status body (features.artifacts.statusLabel). Keep the status span
|
|
3507
|
+
from blowing out the chrome bar when a long detail streams in. */
|
|
3508
|
+
[data-persona-root] .persona-artifact-inline-chrome-lead .persona-artifact-inline-status {
|
|
3509
|
+
min-width: 0;
|
|
3510
|
+
overflow: hidden;
|
|
3511
|
+
white-space: nowrap;
|
|
3512
|
+
text-overflow: ellipsis;
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
[data-persona-root] .persona-artifact-status-detail {
|
|
3516
|
+
color: var(--persona-artifact-inline-muted-color, var(--persona-text-muted, #6b7280));
|
|
3517
|
+
margin-left: 0.375rem;
|
|
3518
|
+
font-variant-numeric: tabular-nums;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
/* Trailing cluster: custom inlineActions, copy, expand. */
|
|
3522
|
+
[data-persona-root] .persona-artifact-inline-chrome-actions {
|
|
3523
|
+
display: flex;
|
|
3524
|
+
align-items: center;
|
|
3525
|
+
gap: 0.25rem;
|
|
3526
|
+
flex: 0 0 auto;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
/* Body wraps the chrome-free preview; padding lives here so the chrome sits
|
|
3530
|
+
flush to the frame edge. */
|
|
3531
|
+
[data-persona-root] .persona-artifact-inline-body {
|
|
3532
|
+
padding: 0.75rem;
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
/* The preview frame (and its 100%-height iframe) is height: 100%, which
|
|
3536
|
+
collapses inside the auto-height inline block; pin a themeable fixed height on
|
|
3537
|
+
the frame instead. Height var chain: inlineBody.height
|
|
3538
|
+
(--persona-artifact-inline-body-height, set per state by artifact-inline.ts) →
|
|
3539
|
+
the legacy --persona-artifact-inline-frame-height override → 320px. The legacy
|
|
3540
|
+
var still wins when the new one is unset (inlineBody.height "auto"), so themes
|
|
3541
|
+
pinned to it keep working. The --sized rule below (equal specificity, declared
|
|
3542
|
+
later) overrides this to 100% when the body wrapper owns the height. */
|
|
3543
|
+
[data-persona-root] .persona-artifact-inline .persona-artifact-frame {
|
|
3544
|
+
height: var(
|
|
3545
|
+
--persona-artifact-inline-body-height,
|
|
3546
|
+
var(--persona-artifact-inline-frame-height, 320px)
|
|
3547
|
+
);
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
/* Inline body height model (features.artifacts.inlineBody). The block root sets
|
|
3551
|
+
--persona-artifact-inline-body-height (px) for the current state; leaving it
|
|
3552
|
+
unset (inlineBody.height "auto") lets the body size to content and the iframe
|
|
3553
|
+
fall back through the chain above. */
|
|
3554
|
+
|
|
3555
|
+
/* Code bodies are full-bleed, matching the pane's source-view treatment (same
|
|
3556
|
+
class the pane toggles): the line-number gutter sits flush against the frame
|
|
3557
|
+
edge. Declared after .persona-artifact-inline-body so padding: 0 wins the
|
|
3558
|
+
specificity tie. */
|
|
3559
|
+
[data-persona-root] .persona-artifact-inline-body.persona-artifact-content-flush {
|
|
3560
|
+
padding: 0;
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
/* Numeric inlineBody.height: the body wrapper owns the reserved height
|
|
3564
|
+
(border-box), so flush code, padded iframe, and padded status bodies all
|
|
3565
|
+
occupy the same outer box and every state swap is layout neutral. Fill-capable
|
|
3566
|
+
content stretches to the wrapper. */
|
|
3567
|
+
[data-persona-root] .persona-artifact-inline-body--sized {
|
|
3568
|
+
height: var(--persona-artifact-inline-body-height, auto);
|
|
3569
|
+
}
|
|
3570
|
+
[data-persona-root] .persona-artifact-inline-body--sized .persona-artifact-source-window--fixed,
|
|
3571
|
+
[data-persona-root] .persona-artifact-inline-body--sized .persona-artifact-frame {
|
|
3572
|
+
height: 100%;
|
|
3573
|
+
}
|
|
3574
|
+
[data-persona-root] .persona-artifact-inline-body--sized .persona-artifact-status-view {
|
|
3575
|
+
min-height: 100%;
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
/* Fixed-height streaming source window: a reserved scroll viewport so streamed
|
|
3579
|
+
source no longer grows an unbounded <pre> and then snaps to the preview. The
|
|
3580
|
+
height comes from the sized body wrapper above (the --fixed class is only
|
|
3581
|
+
ever applied together with it). The bare (non-fixed) window is an inert
|
|
3582
|
+
wrapper (pane path never adds it; the source <pre> sits directly on el
|
|
3583
|
+
there). */
|
|
3584
|
+
[data-persona-root] .persona-artifact-source-window {
|
|
3585
|
+
min-width: 0;
|
|
3586
|
+
}
|
|
3587
|
+
[data-persona-root] .persona-artifact-source-window--fixed {
|
|
3588
|
+
overflow-y: auto;
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3591
|
+
/* Clipped preview window (inlineBody.overflow: "clip"): a fixed-height window
|
|
3592
|
+
showing the top of the document with no internal scroll. Applied together with
|
|
3593
|
+
--fixed (which supplies the reserved height via the --sized body wrapper and
|
|
3594
|
+
the fill-capable detection in artifact-inline.ts); declared after --fixed so
|
|
3595
|
+
this overflow: hidden wins its overflow-y: auto on the specificity tie. */
|
|
3596
|
+
[data-persona-root] .persona-artifact-source-window--clip {
|
|
3597
|
+
overflow: hidden;
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
/* Edge fade masks on the fixed window (top fade signals content clipped above).
|
|
3601
|
+
mask-image works over any themed background; size via --persona-artifact-fade-size
|
|
3602
|
+
(defaults to 40px). */
|
|
3603
|
+
[data-persona-root]
|
|
3604
|
+
.persona-artifact-fade-top:not(.persona-artifact-fade-bottom) {
|
|
3605
|
+
-webkit-mask-image: linear-gradient(
|
|
3606
|
+
to bottom,
|
|
3607
|
+
transparent 0,
|
|
3608
|
+
#000 var(--persona-artifact-fade-size, 40px)
|
|
3609
|
+
);
|
|
3610
|
+
mask-image: linear-gradient(
|
|
3611
|
+
to bottom,
|
|
3612
|
+
transparent 0,
|
|
3613
|
+
#000 var(--persona-artifact-fade-size, 40px)
|
|
3614
|
+
);
|
|
3615
|
+
}
|
|
3616
|
+
[data-persona-root]
|
|
3617
|
+
.persona-artifact-fade-bottom:not(.persona-artifact-fade-top) {
|
|
3618
|
+
-webkit-mask-image: linear-gradient(
|
|
3619
|
+
to top,
|
|
3620
|
+
transparent 0,
|
|
3621
|
+
#000 var(--persona-artifact-fade-size, 40px)
|
|
3622
|
+
);
|
|
3623
|
+
mask-image: linear-gradient(
|
|
3624
|
+
to top,
|
|
3625
|
+
transparent 0,
|
|
3626
|
+
#000 var(--persona-artifact-fade-size, 40px)
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
3629
|
+
[data-persona-root]
|
|
3630
|
+
.persona-artifact-fade-top.persona-artifact-fade-bottom {
|
|
3631
|
+
-webkit-mask-image: linear-gradient(
|
|
3632
|
+
to bottom,
|
|
3633
|
+
transparent 0,
|
|
3634
|
+
#000 var(--persona-artifact-fade-size, 40px),
|
|
3635
|
+
#000 calc(100% - var(--persona-artifact-fade-size, 40px)),
|
|
3636
|
+
transparent 100%
|
|
3637
|
+
);
|
|
3638
|
+
mask-image: linear-gradient(
|
|
3639
|
+
to bottom,
|
|
3640
|
+
transparent 0,
|
|
3641
|
+
#000 var(--persona-artifact-fade-size, 40px),
|
|
3642
|
+
#000 calc(100% - var(--persona-artifact-fade-size, 40px)),
|
|
3643
|
+
transparent 100%
|
|
3644
|
+
);
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
/* Edge fade on the horizontally scrollable tab strip. Visual hint only; the
|
|
3648
|
+
tablist keyboard behavior is the real affordance. Sized via
|
|
3649
|
+
--persona-artifact-tab-fade-size (default 24px). */
|
|
3650
|
+
[data-persona-root]
|
|
3651
|
+
.persona-artifact-tab-fade-start:not(.persona-artifact-tab-fade-end) {
|
|
3652
|
+
-webkit-mask-image: linear-gradient(
|
|
3653
|
+
to right,
|
|
3654
|
+
transparent 0,
|
|
3655
|
+
#000 var(--persona-artifact-tab-fade-size, 24px)
|
|
3656
|
+
);
|
|
3657
|
+
mask-image: linear-gradient(
|
|
3658
|
+
to right,
|
|
3659
|
+
transparent 0,
|
|
3660
|
+
#000 var(--persona-artifact-tab-fade-size, 24px)
|
|
3661
|
+
);
|
|
3662
|
+
}
|
|
3663
|
+
[data-persona-root]
|
|
3664
|
+
.persona-artifact-tab-fade-end:not(.persona-artifact-tab-fade-start) {
|
|
3665
|
+
-webkit-mask-image: linear-gradient(
|
|
3666
|
+
to left,
|
|
3667
|
+
transparent 0,
|
|
3668
|
+
#000 var(--persona-artifact-tab-fade-size, 24px)
|
|
3669
|
+
);
|
|
3670
|
+
mask-image: linear-gradient(
|
|
3671
|
+
to left,
|
|
3672
|
+
transparent 0,
|
|
3673
|
+
#000 var(--persona-artifact-tab-fade-size, 24px)
|
|
3674
|
+
);
|
|
3675
|
+
}
|
|
3676
|
+
[data-persona-root]
|
|
3677
|
+
.persona-artifact-tab-fade-start.persona-artifact-tab-fade-end {
|
|
3678
|
+
-webkit-mask-image: linear-gradient(
|
|
3679
|
+
to right,
|
|
3680
|
+
transparent 0,
|
|
3681
|
+
#000 var(--persona-artifact-tab-fade-size, 24px),
|
|
3682
|
+
#000 calc(100% - var(--persona-artifact-tab-fade-size, 24px)),
|
|
3683
|
+
transparent 100%
|
|
3684
|
+
);
|
|
3685
|
+
mask-image: linear-gradient(
|
|
3686
|
+
to right,
|
|
3687
|
+
transparent 0,
|
|
3688
|
+
#000 var(--persona-artifact-tab-fade-size, 24px),
|
|
3689
|
+
#000 calc(100% - var(--persona-artifact-tab-fade-size, 24px)),
|
|
3690
|
+
transparent 100%
|
|
3691
|
+
);
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
/* Reserved-height status placeholder (inlineBody.streamingView: "status").
|
|
3695
|
+
Numeric height reserves the var; "auto" falls back to a modest 160px min-height
|
|
3696
|
+
so the card doesn't collapse. */
|
|
3697
|
+
[data-persona-root] .persona-artifact-status-view {
|
|
3698
|
+
display: flex;
|
|
3699
|
+
align-items: center;
|
|
3700
|
+
justify-content: center;
|
|
3701
|
+
min-height: var(--persona-artifact-inline-body-height, 160px);
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
/* Complete-state height cap for non-iframe bodies (rendered markdown, source
|
|
3705
|
+
view, component). The iframe path is sized by the iframe rule above instead,
|
|
3706
|
+
so this class is only applied when the completed body has no iframe. */
|
|
3707
|
+
[data-persona-root] .persona-artifact-inline-body--cap {
|
|
3708
|
+
max-height: var(--persona-artifact-inline-body-height, none);
|
|
3709
|
+
overflow-y: auto;
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3027
3712
|
[data-persona-root] .persona-artifact-pane {
|
|
3028
3713
|
border-radius: var(--persona-artifact-pane-radius, 0);
|
|
3029
3714
|
overflow: hidden;
|
|
@@ -3072,23 +3757,71 @@
|
|
|
3072
3757
|
border: var(--persona-artifact-pane-border) !important;
|
|
3073
3758
|
}
|
|
3074
3759
|
|
|
3760
|
+
/* paneAppearance: 'detached': floating card with gap, all-side border, radius, elevation, canvas behind */
|
|
3761
|
+
/* Split gap defaults to --persona-panel-inset from ui.ts; canvas paints behind both columns. */
|
|
3762
|
+
[data-persona-root].persona-artifact-appearance-detached .persona-artifact-split-root {
|
|
3763
|
+
background: var(--persona-panel-canvas-bg);
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
/* Desktop split only (drawer keeps its own chrome). Non-!important so explicit
|
|
3767
|
+
paneBorder / paneShadow / paneBorderRadius overrides still win. */
|
|
3768
|
+
@media (min-width: 641px) {
|
|
3769
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-appearance-detached .persona-artifact-pane {
|
|
3770
|
+
border-radius: var(
|
|
3771
|
+
--persona-artifact-pane-radius,
|
|
3772
|
+
var(--persona-panel-radius, var(--persona-radius-xl, 0.75rem))
|
|
3773
|
+
);
|
|
3774
|
+
border: var(--persona-panel-border, 1px solid var(--persona-border, #e5e7eb));
|
|
3775
|
+
box-shadow: var(
|
|
3776
|
+
--persona-artifact-pane-shadow,
|
|
3777
|
+
var(--persona-panel-shadow, var(--persona-palette-shadows-xl, 0 25px 50px -12px rgba(0, 0, 0, 0.25)))
|
|
3778
|
+
);
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
|
|
3782
|
+
/* chatSurface: 'flush': chat is flat flush background, only the pane floats. The
|
|
3783
|
+
chat has no perimeter inset, so inset the pane on 3 sides (left gap comes from
|
|
3784
|
+
the existing detached split flex gap). Keeps the pane's border/radius/shadow. */
|
|
3785
|
+
@media (min-width: 641px) {
|
|
3786
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-chat-flush .persona-artifact-pane {
|
|
3787
|
+
margin-top: var(--persona-panel-inset);
|
|
3788
|
+
margin-right: var(--persona-panel-inset);
|
|
3789
|
+
margin-bottom: var(--persona-panel-inset);
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3075
3793
|
/*
|
|
3076
|
-
*
|
|
3077
|
-
*
|
|
3794
|
+
* Welded split chrome (panel + seamless): one card. The outer panel carries the
|
|
3795
|
+
* border + radius + shadow (set in ui.ts); each column rounds only its outer
|
|
3796
|
+
* corners and clips, so the columns fill the panel's rounded rect and butt flush
|
|
3797
|
+
* at the seam. Desktop split only (narrowed via :not(.narrow-host) + breakpoint).
|
|
3798
|
+
* Toggled from ui.ts by splitChromeMode(); the pane's flex layout owns gap 0.
|
|
3078
3799
|
*/
|
|
3079
3800
|
@media (min-width: 641px) {
|
|
3080
|
-
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-
|
|
3801
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-welded-split .persona-artifact-split-root {
|
|
3802
|
+
position: relative;
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-welded-split .persona-widget-container {
|
|
3081
3806
|
border-top-right-radius: 0 !important;
|
|
3082
3807
|
border-bottom-right-radius: 0 !important;
|
|
3808
|
+
overflow: hidden;
|
|
3083
3809
|
}
|
|
3084
3810
|
|
|
3085
|
-
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-
|
|
3811
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-welded-split .persona-artifact-pane {
|
|
3086
3812
|
border-top-left-radius: 0 !important;
|
|
3087
3813
|
border-bottom-left-radius: 0 !important;
|
|
3088
|
-
border-top-right-radius: var(--persona-artifact-
|
|
3089
|
-
border-bottom-right-radius: var(--persona-artifact-
|
|
3814
|
+
border-top-right-radius: var(--persona-artifact-welded-outer-radius, var(--persona-panel-radius, var(--persona-radius-xl, 0.75rem))) !important;
|
|
3815
|
+
border-bottom-right-radius: var(--persona-artifact-welded-outer-radius, var(--persona-panel-radius, var(--persona-radius-xl, 0.75rem))) !important;
|
|
3090
3816
|
overflow: hidden;
|
|
3091
3817
|
}
|
|
3818
|
+
|
|
3819
|
+
/* panel appearance: a hairline divider on the pane's chat-facing edge. seamless
|
|
3820
|
+
omits it (it already zeroes border-left). Non-!important so paneBorder /
|
|
3821
|
+
paneBorderLeft overrides win. */
|
|
3822
|
+
[data-persona-root]:not(.persona-artifact-narrow-host).persona-artifact-welded-split.persona-artifact-appearance-panel .persona-artifact-pane {
|
|
3823
|
+
border-left: 1px solid var(--persona-border, #e5e7eb);
|
|
3824
|
+
}
|
|
3092
3825
|
}
|
|
3093
3826
|
|
|
3094
3827
|
/* Narrow floating panel: drawer inside panel (class toggled by JS from panel width) */
|
|
@@ -3789,6 +4522,20 @@
|
|
|
3789
4522
|
gap: 8px;
|
|
3790
4523
|
}
|
|
3791
4524
|
|
|
4525
|
+
/* Configured / agent-pushed suggestion chips belong to the expanded
|
|
4526
|
+
* conversation surface, not the always-on collapsed composer. Keeping the
|
|
4527
|
+
* row in pillRoot lets it sit directly above the textarea without re-entering
|
|
4528
|
+
* the transcript's scrolling region. */
|
|
4529
|
+
.persona-widget-pill-root[data-state="collapsed"] [data-persona-composer-suggestions] {
|
|
4530
|
+
display: none;
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
.persona-widget-pill-root[data-state="expanded"] [data-persona-composer-suggestions] {
|
|
4534
|
+
display: flex;
|
|
4535
|
+
justify-content: center;
|
|
4536
|
+
margin: 0 8px 4px;
|
|
4537
|
+
}
|
|
4538
|
+
|
|
3792
4539
|
/* Attachment previews row (above the pill). AttachmentManager toggles
|
|
3793
4540
|
* display:flex when items are added; default is display:none. */
|
|
3794
4541
|
.persona-pill-composer__previews {
|