@dfosco/storyboard-react 4.2.0-beta.4 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -11
- package/src/AuthModal/AuthModal.jsx +6 -8
- package/src/BranchBar/BranchBar.jsx +20 -6
- package/src/BranchBar/BranchBar.module.css +13 -4
- package/src/BranchBar/useBranches.js +20 -6
- package/src/BranchBar/useBranches.test.js +68 -0
- package/src/CommandPalette/CommandPalette.jsx +480 -187
- package/src/CommandPalette/command-palette.css +142 -78
- package/src/Icon.jsx +157 -58
- package/src/Viewfinder.jsx +562 -207
- package/src/Viewfinder.module.css +434 -93
- package/src/Workspace.jsx +7 -0
- package/src/canvas/CanvasPage.bridge.test.jsx +14 -6
- package/src/canvas/CanvasPage.dragdrop.test.jsx +11 -7
- package/src/canvas/CanvasPage.jsx +739 -219
- package/src/canvas/CanvasPage.module.css +13 -15
- package/src/canvas/CanvasPage.multiselect.test.jsx +17 -6
- package/src/canvas/ConnectorLayer.jsx +121 -165
- package/src/canvas/ConnectorLayer.module.css +69 -0
- package/src/canvas/PageSelector.test.jsx +15 -6
- package/src/canvas/canvasApi.js +68 -2
- package/src/canvas/canvasReloadGuard.test.js +1 -1
- package/src/canvas/connectorGeometry.js +132 -0
- package/src/canvas/hotPoolDevLogs.js +25 -0
- package/src/canvas/useCanvas.js +1 -1
- package/src/canvas/useMarqueeSelect.js +30 -4
- package/src/canvas/widgets/CodePenEmbed.jsx +1 -0
- package/src/canvas/widgets/ComponentSetWidget.jsx +199 -0
- package/src/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/canvas/widgets/ComponentWidget.jsx +1 -0
- package/src/canvas/widgets/CropOverlay.jsx +219 -0
- package/src/canvas/widgets/CropOverlay.module.css +118 -0
- package/src/canvas/widgets/ExpandedPane.jsx +474 -0
- package/src/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/canvas/widgets/FigmaEmbed.jsx +62 -47
- package/src/canvas/widgets/FigmaEmbed.module.css +61 -0
- package/src/canvas/widgets/ImageWidget.jsx +130 -9
- package/src/canvas/widgets/ImageWidget.module.css +30 -0
- package/src/canvas/widgets/LinkPreview.jsx +113 -5
- package/src/canvas/widgets/LinkPreview.module.css +127 -0
- package/src/canvas/widgets/MarkdownBlock.jsx +167 -17
- package/src/canvas/widgets/MarkdownBlock.module.css +148 -0
- package/src/canvas/widgets/PromptWidget.jsx +414 -0
- package/src/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/canvas/widgets/PrototypeEmbed.jsx +77 -39
- package/src/canvas/widgets/PrototypeEmbed.module.css +117 -0
- package/src/canvas/widgets/PrototypeEmbed.test.jsx +2 -2
- package/src/canvas/widgets/ResizeHandle.jsx +17 -6
- package/src/canvas/widgets/StoryWidget.jsx +73 -15
- package/src/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/canvas/widgets/TerminalWidget.jsx +445 -67
- package/src/canvas/widgets/TerminalWidget.module.css +271 -8
- package/src/canvas/widgets/TilesWidget.jsx +300 -0
- package/src/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/canvas/widgets/WidgetChrome.jsx +74 -153
- package/src/canvas/widgets/WidgetChrome.module.css +30 -1
- package/src/canvas/widgets/embedInteraction.test.jsx +24 -26
- package/src/canvas/widgets/expandUtils.js +560 -0
- package/src/canvas/widgets/expandUtils.test.js +155 -0
- package/src/canvas/widgets/index.js +9 -0
- package/src/canvas/widgets/snapshotDisplay.test.jsx +23 -71
- package/src/canvas/widgets/tilePool.js +23 -0
- package/src/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/canvas/widgets/tiles/leaf.png +0 -0
- package/src/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/canvas/widgets/widgetConfig.js +55 -4
- package/src/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/canvas/widgets/widgetProps.js +1 -0
- package/src/context.jsx +48 -20
- package/src/hooks/useConfig.js +14 -0
- package/src/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/hooks/useSceneData.js +1 -0
- package/src/hooks/useThemeState.test.js +1 -1
- package/src/index.js +8 -2
- package/src/story/ComponentSetPage.jsx +186 -0
- package/src/story/ComponentSetPage.module.css +121 -0
- package/src/story/StoryPage.jsx +32 -2
- package/src/vite/data-plugin.js +407 -67
- package/src/vite/data-plugin.test.js +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
padding: 8px;
|
|
3
|
+
user-select: none;
|
|
4
|
+
cursor: default;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.toolbar {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
gap: 4px;
|
|
11
|
+
padding: 4px 0 8px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.toolbarBtn {
|
|
15
|
+
all: unset;
|
|
16
|
+
display: inline-flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
width: 28px;
|
|
20
|
+
height: 28px;
|
|
21
|
+
border-radius: 6px;
|
|
22
|
+
font-size: 14px;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
color: var(--fgColor-default, #1f2328);
|
|
25
|
+
background: var(--bgColor-muted, #f6f8fa);
|
|
26
|
+
transition: background 0.12s ease;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.toolbarBtn:hover {
|
|
30
|
+
background: var(--bgColor-neutral-muted, #d0d7de);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.toolbarBtn:disabled {
|
|
34
|
+
opacity: 0.35;
|
|
35
|
+
cursor: default;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.toolbarLabel {
|
|
39
|
+
font-size: 12px;
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
color: var(--fgColor-muted, #656d76);
|
|
42
|
+
min-width: 32px;
|
|
43
|
+
text-align: center;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.toolbarSep {
|
|
47
|
+
width: 1px;
|
|
48
|
+
height: 16px;
|
|
49
|
+
background: var(--borderColor-muted, #d0d7de);
|
|
50
|
+
margin: 0 4px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.grid {
|
|
54
|
+
display: grid;
|
|
55
|
+
border-radius: 6px;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.tile {
|
|
60
|
+
position: relative;
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
cursor: pointer;
|
|
63
|
+
border: 2px solid transparent;
|
|
64
|
+
border-radius: 4px;
|
|
65
|
+
transition: border-color 0.12s ease, opacity 0.15s ease, transform 0.12s ease;
|
|
66
|
+
background: var(--bgColor-muted, #f6f8fa);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.tile:hover {
|
|
70
|
+
border-color: var(--borderColor-accent-emphasis, #0969da);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.selected {
|
|
74
|
+
border-color: var(--fgColor-accent, #0969da);
|
|
75
|
+
box-shadow: 0 0 0 2px var(--fgColor-accent, #0969da);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.pasteTarget {
|
|
79
|
+
border-color: var(--fgColor-success, #1a7f37);
|
|
80
|
+
box-shadow: 0 0 0 2px var(--fgColor-success, #1a7f37);
|
|
81
|
+
animation: pulse 1s infinite;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.dragOver {
|
|
85
|
+
border-color: var(--fgColor-accent, #0969da);
|
|
86
|
+
background: var(--bgColor-accent-muted, #ddf4ff);
|
|
87
|
+
transform: scale(1.04);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.dragging {
|
|
91
|
+
opacity: 0.4;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.tileImage {
|
|
95
|
+
width: 100%;
|
|
96
|
+
height: 100%;
|
|
97
|
+
object-fit: cover;
|
|
98
|
+
display: block;
|
|
99
|
+
pointer-events: none;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.emptyTile {
|
|
103
|
+
display: block;
|
|
104
|
+
width: 100%;
|
|
105
|
+
height: 100%;
|
|
106
|
+
background: var(--bgColor-muted, #f6f8fa);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.pasteHint {
|
|
110
|
+
position: absolute;
|
|
111
|
+
inset: 0;
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
background: rgba(0, 0, 0, 0.45);
|
|
116
|
+
color: white;
|
|
117
|
+
font-size: 11px;
|
|
118
|
+
font-weight: 600;
|
|
119
|
+
letter-spacing: 0.5px;
|
|
120
|
+
pointer-events: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.hint {
|
|
124
|
+
padding: 6px 0 2px;
|
|
125
|
+
text-align: center;
|
|
126
|
+
font-size: 11px;
|
|
127
|
+
color: var(--fgColor-muted, #656d76);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@keyframes pulse {
|
|
131
|
+
0%, 100% { box-shadow: 0 0 0 2px var(--fgColor-success, #1a7f37); }
|
|
132
|
+
50% { box-shadow: 0 0 0 4px var(--fgColor-success, #1a7f37); }
|
|
133
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useCallback, useRef, useEffect, useSyncExternalStore } from 'react'
|
|
2
2
|
import { Tooltip } from '@primer/react'
|
|
3
|
-
import { EyeIcon as OcticonEye, EyeClosedIcon as OcticonEyeClosed, CodeIcon as OcticonCode, UnwrapIcon as OcticonUnwrap, ImageIcon as OcticonImage, UnfoldIcon as OcticonUnfold, FoldIcon as OcticonFold } from '@primer/octicons-react'
|
|
4
3
|
import { getConnectorConfig, getInteractGate } from './widgetConfig.js'
|
|
4
|
+
import { ICON_REGISTRY } from './widgetIcons.jsx'
|
|
5
5
|
import styles from './WidgetChrome.module.css'
|
|
6
6
|
import overlayStyles from './embedOverlay.module.css'
|
|
7
7
|
|
|
@@ -14,75 +14,6 @@ const STICKY_NOTE_COLORS = {
|
|
|
14
14
|
orange: { bg: '#fff1e5', border: '#d18616', dot: '#e8a844' },
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function DeleteIcon() {
|
|
18
|
-
return (
|
|
19
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
20
|
-
<path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.15l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z" />
|
|
21
|
-
</svg>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function ZoomInIcon() {
|
|
26
|
-
return (
|
|
27
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
28
|
-
<path d="M7.75 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.5v4.25a.75.75 0 0 1-1.5 0V8.5H2.75a.75.75 0 0 1 0-1.5H7V2.75A.75.75 0 0 1 7.75 2Z" />
|
|
29
|
-
</svg>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function ZoomOutIcon() {
|
|
34
|
-
return (
|
|
35
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
36
|
-
<path d="M2.75 7.25h10.5a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5Z" />
|
|
37
|
-
</svg>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function EditIcon() {
|
|
42
|
-
return (
|
|
43
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
44
|
-
<path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z" />
|
|
45
|
-
</svg>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function OpenExternalIcon() {
|
|
50
|
-
return (
|
|
51
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
52
|
-
<path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z" />
|
|
53
|
-
</svg>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function EyeIcon() {
|
|
58
|
-
return <OcticonEye size={12} />
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function EyeClosedIcon() {
|
|
62
|
-
return <OcticonEyeClosed size={12} />
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function CodeIcon() {
|
|
66
|
-
return <OcticonCode size={12} />
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function UnwrapIcon() {
|
|
70
|
-
return <OcticonUnwrap size={12} />
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function ImageIcon() {
|
|
74
|
-
return <OcticonImage size={12} />
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function CopyIcon() {
|
|
78
|
-
return (
|
|
79
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
80
|
-
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z" />
|
|
81
|
-
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z" />
|
|
82
|
-
</svg>
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
17
|
function MoreIcon() {
|
|
87
18
|
return (
|
|
88
19
|
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
@@ -91,14 +22,6 @@ function MoreIcon() {
|
|
|
91
22
|
)
|
|
92
23
|
}
|
|
93
24
|
|
|
94
|
-
function LinkIcon() {
|
|
95
|
-
return (
|
|
96
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
97
|
-
<path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z" />
|
|
98
|
-
</svg>
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
25
|
function ChevronDownIcon() {
|
|
103
26
|
return (
|
|
104
27
|
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
@@ -107,62 +30,6 @@ function ChevronDownIcon() {
|
|
|
107
30
|
)
|
|
108
31
|
}
|
|
109
32
|
|
|
110
|
-
function DownloadIcon() {
|
|
111
|
-
return (
|
|
112
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
113
|
-
<path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z" />
|
|
114
|
-
<path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06Z" />
|
|
115
|
-
</svg>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function ExpandIcon() {
|
|
120
|
-
return (
|
|
121
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
122
|
-
<path d="M1.75 10a.75.75 0 0 1 .75.75v2.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 0 1.5h-2.5A1.75 1.75 0 0 1 1 13.25v-2.5a.75.75 0 0 1 .75-.75Zm12.5 0a.75.75 0 0 1 .75.75v2.5A1.75 1.75 0 0 1 13.25 15h-2.5a.75.75 0 0 1 0-1.5h2.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 .75-.75ZM2.75 1h2.5a.75.75 0 0 1 0 1.5h-2.5a.25.25 0 0 0-.25.25v2.5a.75.75 0 0 1-1.5 0v-2.5C1 1.784 1.784 1 2.75 1Zm10.5 0C14.216 1 15 1.784 15 2.75v2.5a.75.75 0 0 1-1.5 0v-2.5a.25.25 0 0 0-.25-.25h-2.5a.75.75 0 0 1 0-1.5Z" />
|
|
123
|
-
</svg>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function SyncIcon() {
|
|
128
|
-
return (
|
|
129
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
130
|
-
<path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z" />
|
|
131
|
-
</svg>
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function UnfoldIcon() {
|
|
136
|
-
return <OcticonUnfold size={12} />
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function FoldIcon() {
|
|
140
|
-
return <OcticonFold size={12} />
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** Icon registry — maps icon name strings from config to React components. */
|
|
144
|
-
const ICON_REGISTRY = {
|
|
145
|
-
'trash': DeleteIcon,
|
|
146
|
-
'zoom-in': ZoomInIcon,
|
|
147
|
-
'zoom-out': ZoomOutIcon,
|
|
148
|
-
'edit': EditIcon,
|
|
149
|
-
'open-external': OpenExternalIcon,
|
|
150
|
-
'eye': EyeIcon,
|
|
151
|
-
'eye-closed': EyeClosedIcon,
|
|
152
|
-
'code': CodeIcon,
|
|
153
|
-
'unwrap': UnwrapIcon,
|
|
154
|
-
'image': ImageIcon,
|
|
155
|
-
'copy': CopyIcon,
|
|
156
|
-
'link': LinkIcon,
|
|
157
|
-
'more': MoreIcon,
|
|
158
|
-
'chevron-down': ChevronDownIcon,
|
|
159
|
-
'download': DownloadIcon,
|
|
160
|
-
'expand': ExpandIcon,
|
|
161
|
-
'sync': SyncIcon,
|
|
162
|
-
'unfold': UnfoldIcon,
|
|
163
|
-
'fold': FoldIcon,
|
|
164
|
-
}
|
|
165
|
-
|
|
166
33
|
/** Danger-styled actions in the overflow menu. */
|
|
167
34
|
const DANGER_ACTIONS = new Set(['delete'])
|
|
168
35
|
|
|
@@ -228,7 +95,7 @@ function WidgetOverflowMenu({ widgetId, menuFeatures, onAction }) {
|
|
|
228
95
|
const canvasId = window.__storyboardCanvasBridgeState?.canvasId || ''
|
|
229
96
|
navigator.clipboard.writeText(`${canvasId}::${widgetId}`).catch(() => {})
|
|
230
97
|
} else {
|
|
231
|
-
onAction?.(action)
|
|
98
|
+
onAction?.(action, { altKey: altHeld })
|
|
232
99
|
}
|
|
233
100
|
setOpen(false)
|
|
234
101
|
}, [widgetId, onAction, altHeld])
|
|
@@ -319,7 +186,7 @@ function DropdownFeature({ feature, onAction }) {
|
|
|
319
186
|
className={styles.overflowItem}
|
|
320
187
|
onClick={(e) => {
|
|
321
188
|
e.stopPropagation()
|
|
322
|
-
onAction?.(action)
|
|
189
|
+
onAction?.(action, { altKey: altHeld })
|
|
323
190
|
setOpen(false)
|
|
324
191
|
}}
|
|
325
192
|
>
|
|
@@ -338,13 +205,35 @@ function DropdownFeature({ feature, onAction }) {
|
|
|
338
205
|
}
|
|
339
206
|
|
|
340
207
|
/**
|
|
341
|
-
* ColorPicker feature button — shows a dot that reveals color options on
|
|
208
|
+
* ColorPicker feature button — shows a dot that reveals color options on click.
|
|
209
|
+
* Closes on click-outside or Escape.
|
|
342
210
|
*/
|
|
343
211
|
function ColorPickerFeature({ currentColor, options, onColorChange }) {
|
|
344
212
|
const palette = STICKY_NOTE_COLORS[currentColor] ?? STICKY_NOTE_COLORS.yellow
|
|
213
|
+
const [open, setOpen] = useState(false)
|
|
214
|
+
const wrapperRef = useRef(null)
|
|
215
|
+
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (!open) return
|
|
218
|
+
function handleClickOutside(e) {
|
|
219
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
220
|
+
setOpen(false)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function handleEscape(e) {
|
|
224
|
+
if (e.key === 'Escape') setOpen(false)
|
|
225
|
+
}
|
|
226
|
+
document.addEventListener('pointerdown', handleClickOutside, true)
|
|
227
|
+
document.addEventListener('keydown', handleEscape)
|
|
228
|
+
return () => {
|
|
229
|
+
document.removeEventListener('pointerdown', handleClickOutside, true)
|
|
230
|
+
document.removeEventListener('keydown', handleEscape)
|
|
231
|
+
}
|
|
232
|
+
}, [open])
|
|
345
233
|
|
|
346
234
|
return (
|
|
347
235
|
<div
|
|
236
|
+
ref={wrapperRef}
|
|
348
237
|
className={styles.colorPickerWrapper}
|
|
349
238
|
onMouseDown={(e) => e.stopPropagation()}
|
|
350
239
|
onPointerDown={(e) => e.stopPropagation()}
|
|
@@ -354,10 +243,11 @@ function ColorPickerFeature({ currentColor, options, onColorChange }) {
|
|
|
354
243
|
style={{ background: palette.dot }}
|
|
355
244
|
aria-label="Change color"
|
|
356
245
|
title="Change color"
|
|
246
|
+
onClick={() => setOpen((prev) => !prev)}
|
|
357
247
|
>
|
|
358
248
|
<span className={styles.colorDotInner} style={{ background: palette.dot }} />
|
|
359
249
|
</button>
|
|
360
|
-
<div className={styles.colorPopup}>
|
|
250
|
+
<div className={`${styles.colorPopup} ${open ? styles.colorPopupOpen : ''}`}>
|
|
361
251
|
{(options || Object.keys(STICKY_NOTE_COLORS)).map((colorName) => {
|
|
362
252
|
const c = STICKY_NOTE_COLORS[colorName]
|
|
363
253
|
if (!c) return null
|
|
@@ -369,6 +259,7 @@ function ColorPickerFeature({ currentColor, options, onColorChange }) {
|
|
|
369
259
|
onClick={(e) => {
|
|
370
260
|
e.stopPropagation()
|
|
371
261
|
onColorChange(colorName)
|
|
262
|
+
setOpen(false)
|
|
372
263
|
}}
|
|
373
264
|
title={colorName}
|
|
374
265
|
aria-label={`Set color to ${colorName}`}
|
|
@@ -433,13 +324,13 @@ export default function WidgetChrome({
|
|
|
433
324
|
e.stopPropagation()
|
|
434
325
|
// Standard actions go through onAction (handled by CanvasPage)
|
|
435
326
|
if (actionId === 'delete' || actionId === 'copy') {
|
|
436
|
-
onAction?.(actionId)
|
|
327
|
+
onAction?.(actionId, { altKey: e.altKey })
|
|
437
328
|
return
|
|
438
329
|
}
|
|
439
330
|
// Widget-specific actions go through the widget's imperative ref
|
|
440
331
|
if (widgetRef?.current?.handleAction) {
|
|
441
|
-
widgetRef.current.handleAction(actionId)
|
|
442
|
-
return
|
|
332
|
+
const handled = widgetRef.current.handleAction(actionId)
|
|
333
|
+
if (handled !== false) return
|
|
443
334
|
}
|
|
444
335
|
// Fallback to generic handler
|
|
445
336
|
onAction?.(actionId)
|
|
@@ -515,7 +406,7 @@ export default function WidgetChrome({
|
|
|
515
406
|
>
|
|
516
407
|
<div ref={slotRef} className={`tc-drag-surface ${styles.widgetSlot} ${selected ? styles.widgetSlotSelected : ''} ${multiSelected ? styles.widgetSlotMultiSelected : ''}`} data-widget-selected={selected || undefined} data-widget-interacting={interacting || undefined}>
|
|
517
408
|
{children}
|
|
518
|
-
{gate.enabled && !interacting && (
|
|
409
|
+
{gate.enabled && !interacting && !readOnly && (
|
|
519
410
|
<div
|
|
520
411
|
className={overlayStyles.interactOverlay}
|
|
521
412
|
onClick={handleGateClick}
|
|
@@ -560,6 +451,7 @@ export default function WidgetChrome({
|
|
|
560
451
|
<div className={`${styles.toolbarContent} ${showToolbar ? styles.toolbarContentVisible : ''}`}>
|
|
561
452
|
{showFeatures && (
|
|
562
453
|
<div className={styles.featureButtons}>
|
|
454
|
+
{/* eslint-disable-next-line react-hooks/refs */}
|
|
563
455
|
{features.map((feature) => {
|
|
564
456
|
// Menu features are rendered in WidgetOverflowMenu
|
|
565
457
|
if (feature.menu) return null
|
|
@@ -581,11 +473,16 @@ export default function WidgetChrome({
|
|
|
581
473
|
|
|
582
474
|
// Toggle-private: swap icon/label based on current state
|
|
583
475
|
if (feature.action === 'toggle-private') {
|
|
476
|
+
const isTerminal = widgetType === 'terminal' || widgetType === 'agent'
|
|
584
477
|
if (widgetProps?.private) {
|
|
585
478
|
Icon = ICON_REGISTRY['eye-closed']
|
|
586
|
-
label =
|
|
479
|
+
label = isTerminal
|
|
480
|
+
? 'Private terminal — snapshots hidden from git'
|
|
481
|
+
: 'Private image — only visible locally'
|
|
587
482
|
} else {
|
|
588
|
-
label =
|
|
483
|
+
label = isTerminal
|
|
484
|
+
? 'Public terminal — snapshots committed to git'
|
|
485
|
+
: 'Published image — deployed with canvas'
|
|
589
486
|
}
|
|
590
487
|
}
|
|
591
488
|
|
|
@@ -594,10 +491,34 @@ export default function WidgetChrome({
|
|
|
594
491
|
label = 'Show component'
|
|
595
492
|
}
|
|
596
493
|
|
|
494
|
+
// Expand-output toggle: swap icon/label, hide when no session
|
|
495
|
+
if (feature.action === 'expand-output') {
|
|
496
|
+
const hasSession = widgetRef?.current?.getState?.('hasSession')
|
|
497
|
+
if (!hasSession) return null
|
|
498
|
+
const isActive = widgetRef?.current?.getState?.('showOutput')
|
|
499
|
+
if (isActive) {
|
|
500
|
+
Icon = ICON_REGISTRY['fold']
|
|
501
|
+
label = 'Hide output'
|
|
502
|
+
} else {
|
|
503
|
+
label = 'Show output'
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Open-terminal: hide when no session
|
|
508
|
+
if (feature.action === 'open-terminal') {
|
|
509
|
+
const hasSession = widgetRef?.current?.getState?.('hasSession')
|
|
510
|
+
if (!hasSession) return null
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Determine active state for toggle buttons
|
|
514
|
+
const isActive = feature.active || (
|
|
515
|
+
feature.action === 'expand-output' && widgetRef?.current?.getState?.('showOutput')
|
|
516
|
+
)
|
|
517
|
+
|
|
597
518
|
return (
|
|
598
519
|
<Tooltip key={feature.id} text={label} direction="n">
|
|
599
520
|
<button
|
|
600
|
-
className={styles.featureBtn}
|
|
521
|
+
className={`${styles.featureBtn}${isActive ? ` ${styles.featureBtnActive}` : ''}`}
|
|
601
522
|
onClick={(e) => handleActionClick(feature.action, e)}
|
|
602
523
|
aria-label={label}
|
|
603
524
|
>
|
|
@@ -612,12 +533,12 @@ export default function WidgetChrome({
|
|
|
612
533
|
<DropdownFeature
|
|
613
534
|
key={feature.id}
|
|
614
535
|
feature={feature}
|
|
615
|
-
onAction={(actionId) => {
|
|
536
|
+
onAction={(actionId, opts) => {
|
|
616
537
|
if (widgetRef?.current?.handleAction) {
|
|
617
|
-
widgetRef.current.handleAction(actionId)
|
|
618
|
-
|
|
619
|
-
onAction?.(actionId)
|
|
538
|
+
const handled = widgetRef.current.handleAction(actionId)
|
|
539
|
+
if (handled !== false) return
|
|
620
540
|
}
|
|
541
|
+
onAction?.(actionId, opts)
|
|
621
542
|
}}
|
|
622
543
|
/>
|
|
623
544
|
)
|
|
@@ -629,13 +550,13 @@ export default function WidgetChrome({
|
|
|
629
550
|
<WidgetOverflowMenu
|
|
630
551
|
widgetId={widgetId}
|
|
631
552
|
menuFeatures={menuFeatures}
|
|
632
|
-
onAction={(actionId) => {
|
|
553
|
+
onAction={(actionId, opts) => {
|
|
633
554
|
// Route overflow menu actions through the widget ref first
|
|
634
555
|
if (actionId !== 'delete' && actionId !== 'copy' && widgetRef?.current?.handleAction) {
|
|
635
|
-
widgetRef.current.handleAction(actionId)
|
|
636
|
-
|
|
637
|
-
onAction?.(actionId)
|
|
556
|
+
const handled = widgetRef.current.handleAction(actionId)
|
|
557
|
+
if (handled !== false) return
|
|
638
558
|
}
|
|
559
|
+
onAction?.(actionId, opts)
|
|
639
560
|
}}
|
|
640
561
|
/>
|
|
641
562
|
)}
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
pointer-events: auto;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/* Invisible expanded hit area — 15px padding around the visible dot */
|
|
23
|
+
.anchorPort::before {
|
|
24
|
+
content: '';
|
|
25
|
+
position: absolute;
|
|
26
|
+
top: -15px;
|
|
27
|
+
left: -15px;
|
|
28
|
+
right: -15px;
|
|
29
|
+
bottom: -15px;
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
.chromeContainer:hover .anchorPort {
|
|
23
33
|
opacity: 0.6;
|
|
24
34
|
}
|
|
@@ -183,6 +193,25 @@
|
|
|
183
193
|
border-color: var(--borderColor-default, #484f58);
|
|
184
194
|
}
|
|
185
195
|
|
|
196
|
+
.featureBtnActive {
|
|
197
|
+
background: var(--bgColor-accent-emphasis, #0969da);
|
|
198
|
+
border-color: var(--bgColor-accent-emphasis, #0969da);
|
|
199
|
+
color: var(--fgColor-onEmphasis, #ffffff);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
:global([data-sb-canvas-theme^='dark']) .featureBtnActive {
|
|
203
|
+
background: var(--bgColor-accent-emphasis, #388bfd);
|
|
204
|
+
border-color: var(--bgColor-accent-emphasis, #388bfd);
|
|
205
|
+
color: var(--fgColor-onEmphasis, #ffffff);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.featureBtnActive:hover {
|
|
209
|
+
background: var(--bgColor-accent-emphasis, #0969da);
|
|
210
|
+
border-color: var(--bgColor-accent-emphasis, #0969da);
|
|
211
|
+
color: var(--fgColor-onEmphasis, #ffffff);
|
|
212
|
+
filter: brightness(1.1);
|
|
213
|
+
}
|
|
214
|
+
|
|
186
215
|
/* Select handle — right-aligned rounded rect */
|
|
187
216
|
.selectHandle {
|
|
188
217
|
all: unset;
|
|
@@ -269,7 +298,7 @@
|
|
|
269
298
|
0 4px 12px rgba(0, 0, 0, 0.45);
|
|
270
299
|
}
|
|
271
300
|
|
|
272
|
-
.
|
|
301
|
+
.colorPopupOpen {
|
|
273
302
|
opacity: 1;
|
|
274
303
|
pointer-events: auto;
|
|
275
304
|
}
|
|
@@ -56,72 +56,70 @@ describe('Embed interaction overlay', () => {
|
|
|
56
56
|
resizable: false,
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
it('renders "Click to
|
|
59
|
+
it('renders "Click to interact" hint when no snapshot exists', () => {
|
|
60
60
|
render(<PrototypeEmbed {...defaultProps} />)
|
|
61
61
|
|
|
62
|
-
const hint = screen.getByText('Click to
|
|
62
|
+
const hint = screen.getByText('Click to interact')
|
|
63
63
|
expect(hint).toBeInTheDocument()
|
|
64
|
-
// CSS modules mangle class names, just check the element exists
|
|
65
64
|
})
|
|
66
65
|
|
|
67
66
|
it('enters interactive mode on single click (not double-click)', async () => {
|
|
68
67
|
const { container } = render(<PrototypeEmbed {...defaultProps} />)
|
|
69
68
|
|
|
70
|
-
// Overlay should exist before interaction
|
|
71
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
69
|
+
// Overlay should exist before interaction; iframe is always rendered
|
|
70
|
+
const overlay = screen.getByRole('button', { name: /click to interact with prototype/i })
|
|
72
71
|
expect(overlay).toBeInTheDocument()
|
|
73
|
-
expect(container.querySelector('iframe')).
|
|
74
|
-
expect(screen.getByText('Design Overview')).toBeInTheDocument()
|
|
72
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
75
73
|
|
|
76
74
|
// Single click should remove the overlay (enter interactive mode)
|
|
77
75
|
fireEvent.click(overlay)
|
|
78
76
|
|
|
79
77
|
// Overlay should no longer exist
|
|
80
|
-
expect(screen.queryByRole('button', { name: /click to
|
|
78
|
+
expect(screen.queryByRole('button', { name: /click to interact/i })).not.toBeInTheDocument()
|
|
81
79
|
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
82
80
|
|
|
83
81
|
fireEvent.pointerDown(document.body)
|
|
84
|
-
expect(screen.getByRole('button', { name: /click to
|
|
85
|
-
expect(container.querySelector('iframe')).
|
|
82
|
+
expect(screen.getByRole('button', { name: /click to interact with prototype/i })).toBeInTheDocument()
|
|
83
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
86
84
|
})
|
|
87
85
|
|
|
88
86
|
it('does not enter interactive mode on shift+click (preserves multi-select)', () => {
|
|
89
87
|
render(<PrototypeEmbed {...defaultProps} />)
|
|
90
88
|
|
|
91
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
89
|
+
const overlay = screen.getByRole('button', { name: /click to interact with prototype/i })
|
|
92
90
|
fireEvent.click(overlay, { shiftKey: true })
|
|
93
91
|
|
|
94
92
|
// Overlay should still exist (did not enter interactive mode)
|
|
95
|
-
expect(screen.getByRole('button', { name: /click to
|
|
93
|
+
expect(screen.getByRole('button', { name: /click to interact with prototype/i })).toBeInTheDocument()
|
|
96
94
|
})
|
|
97
95
|
|
|
98
96
|
it('does not enter interactive mode on meta+click (preserves multi-select)', () => {
|
|
99
97
|
render(<PrototypeEmbed {...defaultProps} />)
|
|
100
98
|
|
|
101
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
99
|
+
const overlay = screen.getByRole('button', { name: /click to interact with prototype/i })
|
|
102
100
|
fireEvent.click(overlay, { metaKey: true })
|
|
103
101
|
|
|
104
|
-
expect(screen.getByRole('button', { name: /click to
|
|
102
|
+
expect(screen.getByRole('button', { name: /click to interact with prototype/i })).toBeInTheDocument()
|
|
105
103
|
})
|
|
106
104
|
|
|
107
105
|
it('supports keyboard interaction (Enter key) with event prevention', () => {
|
|
108
106
|
render(<PrototypeEmbed {...defaultProps} />)
|
|
109
107
|
|
|
110
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
108
|
+
const overlay = screen.getByRole('button', { name: /click to interact with prototype/i })
|
|
111
109
|
const event = { key: 'Enter', preventDefault: vi.fn(), stopPropagation: vi.fn() }
|
|
112
110
|
fireEvent.keyDown(overlay, event)
|
|
113
111
|
|
|
114
|
-
expect(screen.queryByRole('button', { name: /click to
|
|
112
|
+
expect(screen.queryByRole('button', { name: /click to interact/i })).not.toBeInTheDocument()
|
|
115
113
|
})
|
|
116
114
|
|
|
117
115
|
it('supports keyboard interaction (Space key) with event prevention', () => {
|
|
118
116
|
render(<PrototypeEmbed {...defaultProps} />)
|
|
119
117
|
|
|
120
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
118
|
+
const overlay = screen.getByRole('button', { name: /click to interact with prototype/i })
|
|
121
119
|
const event = { key: ' ', preventDefault: vi.fn(), stopPropagation: vi.fn() }
|
|
122
120
|
fireEvent.keyDown(overlay, event)
|
|
123
121
|
|
|
124
|
-
expect(screen.queryByRole('button', { name: /click to
|
|
122
|
+
expect(screen.queryByRole('button', { name: /click to interact/i })).not.toBeInTheDocument()
|
|
125
123
|
})
|
|
126
124
|
})
|
|
127
125
|
|
|
@@ -143,7 +141,7 @@ describe('Embed interaction overlay', () => {
|
|
|
143
141
|
const { container } = render(<FigmaEmbed {...defaultProps} />)
|
|
144
142
|
|
|
145
143
|
const overlay = screen.getByRole('button', { name: /click to interact/i })
|
|
146
|
-
expect(container.querySelector('iframe')).
|
|
144
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
147
145
|
fireEvent.click(overlay)
|
|
148
146
|
|
|
149
147
|
expect(screen.queryByRole('button', { name: /click to interact/i })).not.toBeInTheDocument()
|
|
@@ -151,7 +149,7 @@ describe('Embed interaction overlay', () => {
|
|
|
151
149
|
|
|
152
150
|
fireEvent.pointerDown(document.body)
|
|
153
151
|
expect(screen.getByRole('button', { name: /click to interact/i })).toBeInTheDocument()
|
|
154
|
-
expect(container.querySelector('iframe')).
|
|
152
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
155
153
|
})
|
|
156
154
|
})
|
|
157
155
|
|
|
@@ -162,20 +160,20 @@ describe('Embed interaction overlay', () => {
|
|
|
162
160
|
resizable: false,
|
|
163
161
|
}
|
|
164
162
|
|
|
165
|
-
it('mounts iframe
|
|
163
|
+
it('mounts iframe and shows overlay initially, removes overlay on click', () => {
|
|
166
164
|
const { container } = render(<StoryWidget {...defaultProps} />)
|
|
167
165
|
|
|
168
|
-
const overlay = screen.getByRole('button', { name: /click to
|
|
169
|
-
expect(container.querySelector('iframe')).
|
|
166
|
+
const overlay = screen.getByRole('button', { name: /click to interact$/i })
|
|
167
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
170
168
|
|
|
171
169
|
fireEvent.click(overlay)
|
|
172
170
|
|
|
173
|
-
expect(screen.queryByRole('button', { name: /click to
|
|
171
|
+
expect(screen.queryByRole('button', { name: /click to interact/i })).not.toBeInTheDocument()
|
|
174
172
|
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
175
173
|
|
|
176
174
|
fireEvent.pointerDown(document.body)
|
|
177
|
-
expect(screen.getByRole('button', { name: /click to
|
|
178
|
-
expect(container.querySelector('iframe')).
|
|
175
|
+
expect(screen.getByRole('button', { name: /click to interact$/i })).toBeInTheDocument()
|
|
176
|
+
expect(container.querySelector('iframe')).toBeInTheDocument()
|
|
179
177
|
})
|
|
180
178
|
})
|
|
181
179
|
|