pager-widget 1.0.11-alpha.9 → 1.0.13
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/index.css +1 -1
- package/dist/index.html +40 -0
- package/dist/index.js +8 -8
- package/dist/react-parcel.9f367d21.css +2970 -0
- package/dist/react-parcel.9f367d21.css.map +1 -0
- package/dist/react-parcel.js +231527 -0
- package/dist/react-parcel.js.map +1 -0
- package/dist/server.html +33 -39
- package/out/AgentFeedbackButtonWrapper.js +15 -0
- package/out/App.js +28 -0
- package/out/BotMain.js +91 -0
- package/out/ButtonsWrapper.js +29 -0
- package/out/ChatPage.js +9 -0
- package/out/ChatPageContent.js +131 -0
- package/out/ChatPageHeader.js +267 -0
- package/out/ChatPageInput.js +29 -0
- package/out/ChatWidget.js +17 -0
- package/out/Consent.js +66 -0
- package/out/CountryDropdown.js +31 -0
- package/out/Form.js +238 -0
- package/out/HomePage.js +11 -0
- package/out/HomePageContent.js +32 -0
- package/out/HomePageFooter.js +87 -0
- package/out/HomePageHeader.js +66 -0
- package/out/InputField.js +80 -0
- package/out/Markdown.js +126 -0
- package/out/Message.js +197 -0
- package/out/MessagesT.js +2 -0
- package/out/NewRecentMessagePage.js +525 -0
- package/out/NewRecentMessageTab.js +23 -0
- package/out/ReceivedMessage.js +211 -0
- package/out/RecentMessageDetail.js +178 -0
- package/out/RecentMessageList.js +112 -0
- package/out/RecentMessageListCard.js +20 -0
- package/out/RecentMessageListHeader.js +156 -0
- package/out/RecentMessagePage.js +183 -0
- package/out/RecentMessageTab.js +35 -0
- package/out/WidgetMessage.js +14 -0
- package/out/WidgetToggleButton.js +191 -0
- package/out/WidgetType.js +2 -0
- package/out/assets/icons/pikaicons-react.js +17475 -0
- package/out/components/ConsentForm.js +7 -0
- package/out/components/CustomTooltip.js +34 -0
- package/out/hooks/useChatHistoryExists.js +32 -0
- package/out/hooks/useChatHistoryListExist.js +81 -0
- package/out/hooks/useChatScroll.js +14 -0
- package/out/hooks/useCurrentConversationExists.js +88 -0
- package/out/hooks/useInitialMessage.js +33 -0
- package/out/hooks/useMessage.js +230 -0
- package/out/hooks/useMessageReceiver.js +183 -0
- package/out/hooks/usePopupAnimation.js +20 -0
- package/out/hooks/useSocket.js +19 -0
- package/out/hooks/useSocketContext.js +81 -0
- package/out/hooks/useWidgetDimension.js +41 -0
- package/out/hooks/useWidgetToggle.js +22 -0
- package/out/index.js +31 -0
- package/out/markdown/CodeCopy.js +22 -0
- package/out/markdown/CodeHighlight.js +58 -0
- package/out/markdown/PagerMarkdown.js +36 -0
- package/out/markdown/pager_md.js +152 -0
- package/out/onscreenNotificationPopup.js +23 -0
- package/out/socket.js +11 -0
- package/out/utils/checkConversationExit.js +24 -0
- package/out/utils/convertTime.js +43 -0
- package/out/utils/sendInitialMessage.js +82 -0
- package/out/widget.js +21 -0
- package/out/widgetConfigStore.js +205 -0
- package/out/widgetConfigStore2.js +569 -0
- package/out/widgetControlstore.js +23 -0
- package/out/widgetStateHandler.js +106 -0
- package/out/widgetStore.js +171 -0
- package/out/widgetUserStore.js +47 -0
- package/package.json +3 -3
- package/server.html +33 -39
- package/.husky/pre-commit +0 -4
- package/docs/issues/001-use-widget-resize-hook.md +0 -51
- package/docs/issues/002-embed-snippet-container-resize.md +0 -81
- package/docs/prd/0001-iframe-resize-scroll-through.md +0 -333
- package/test-iframe-resize.html +0 -74
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
# PRD: iframe Container Resize for Page Scroll-Through
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## Problem Statement
|
|
6
|
-
|
|
7
|
-
The Pager Widget is embedded inside an `<iframe>` to bypass SharePoint's Content-Security-Policy. The iframe is styled as `position: fixed; width: 100%; height: 100%; bottom: 0; right: 0; z-index: 9999` — covering the entire viewport.
|
|
8
|
-
|
|
9
|
-
This creates a critical UX bug:
|
|
10
|
-
|
|
11
|
-
- The iframe captures **all** pointer events on the page, even though the visible widget occupies only a small area (a launcher button when collapsed, or a chat panel when open).
|
|
12
|
-
- Users **cannot scroll** the host page.
|
|
13
|
-
- Users **cannot click** links, buttons, or any other interactive elements on the page behind the iframe.
|
|
14
|
-
- The page is effectively frozen except for interaction with the widget itself.
|
|
15
|
-
|
|
16
|
-
The widget is supposed to be a floating assistant, not a page takeover.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Architecture (Two-Tier Iframe Model)
|
|
21
|
-
|
|
22
|
-
Replace the full-viewport iframe with a two-tier iframe pattern:
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
Customer's SharePoint page
|
|
26
|
-
│
|
|
27
|
-
└── <iframe src="https://.../embed/{widget_id}"> ← outer iframe (small, sized to content)
|
|
28
|
-
│
|
|
29
|
-
└── server.html (CONTAINER PAGE, served by backend)
|
|
30
|
-
│
|
|
31
|
-
├── div#pager-widget-container
|
|
32
|
-
│ position:fixed; bottom:right; min 60×60px
|
|
33
|
-
│ dynamically resized via postMessage
|
|
34
|
-
│ │
|
|
35
|
-
│ └── <iframe src="https://.../wgt-hook/embed/..."> ← inner iframe
|
|
36
|
-
│ │
|
|
37
|
-
│ └── Widget React App
|
|
38
|
-
│ └── useWidgetResize (ResizeObserver → postMessage)
|
|
39
|
-
│
|
|
40
|
-
└── Message listener: resizes div#pager-widget-container
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
The outer iframe is sized by SharePoint's web part to match however the
|
|
44
|
-
back end decides to size it. The container page (`server.html`) contains
|
|
45
|
-
a fixed-position container div that starts at launcher size and is
|
|
46
|
-
dynamically resized when the widget reports its actual dimensions.
|
|
47
|
-
|
|
48
|
-
**Result:**
|
|
49
|
-
- The outer iframe is small (matches widget's visible area) → 99% of the SharePoint page is free for scrolling/clicks.
|
|
50
|
-
- When the widget is **collapsed** → container is ~60×60px → only the launcher is visible.
|
|
51
|
-
- When the widget is **open** → container is ~448×637px → only the chat panel area captures events.
|
|
52
|
-
- The page is never blocked from scrolling or clicking outside the widget's visible area.
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## User Stories
|
|
57
|
-
|
|
58
|
-
1. As a page visitor, I want to scroll the content behind the widget launcher or chat panel, so that I can read long articles, forms, or product pages without the widget blocking me.
|
|
59
|
-
|
|
60
|
-
2. As a page visitor, I want to click on links, buttons, and form fields on the page while the widget is present (even when open in a corner), so that I can interact with the page normally.
|
|
61
|
-
|
|
62
|
-
3. As a page visitor, I want to click the widget's launcher button to open the chat, so that I can talk to the AI assistant when I choose to.
|
|
63
|
-
|
|
64
|
-
4. As a page visitor, I want to click outside the chat panel (or hit close) to collapse the widget and return to full page interaction, so that I'm not stuck in the chat.
|
|
65
|
-
|
|
66
|
-
5. As a developer, I want the widget to tell the parent page its current dimensions, so that the iframe container can be resized precisely to match what the user sees.
|
|
67
|
-
|
|
68
|
-
6. As a developer, I want the resize logic to be in one place (the toggle handler), so that it's simple to maintain and debug.
|
|
69
|
-
|
|
70
|
-
7. As a developer, I want the embed snippet to work for any customer without requiring them to write custom JavaScript, so that adoption is seamless.
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Implementation Decisions
|
|
75
|
-
|
|
76
|
-
### Module 1: Widget Frontend — ResizeObserver-based Hook
|
|
77
|
-
|
|
78
|
-
**File**: `src/hooks/useWidgetResize.ts`
|
|
79
|
-
|
|
80
|
-
**Purpose**: Send the widget's current rendered dimensions to the parent page whenever the widget's DOM size changes — toggle, expand, window resize, or any layout shift.
|
|
81
|
-
|
|
82
|
-
**Behavior**:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
// src/hooks/useWidgetResize.ts
|
|
86
|
-
import { useEffect } from 'react'
|
|
87
|
-
|
|
88
|
-
export function useWidgetResize() {
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
const el = document.querySelector('.pager-widget-root')
|
|
91
|
-
if (!el || window.parent === window) return
|
|
92
|
-
|
|
93
|
-
let rafId: number | null = null
|
|
94
|
-
const observer = new ResizeObserver(([entry]) => {
|
|
95
|
-
if (rafId) return // throttle to one rAF at a time
|
|
96
|
-
rafId = requestAnimationFrame(() => {
|
|
97
|
-
rafId = null
|
|
98
|
-
const { width, height } = entry.contentRect
|
|
99
|
-
if (width === 0 || height === 0) return
|
|
100
|
-
window.parent.postMessage(
|
|
101
|
-
{
|
|
102
|
-
type: 'widgetResize',
|
|
103
|
-
width: Math.ceil(width),
|
|
104
|
-
height: Math.ceil(height),
|
|
105
|
-
},
|
|
106
|
-
'*'
|
|
107
|
-
)
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
observer.observe(el)
|
|
111
|
-
|
|
112
|
-
// Fire initial size on mount
|
|
113
|
-
requestAnimationFrame(() => {
|
|
114
|
-
const rect = el.getBoundingClientRect()
|
|
115
|
-
if (rect.width > 0 && rect.height > 0) {
|
|
116
|
-
window.parent.postMessage(
|
|
117
|
-
{
|
|
118
|
-
type: 'widgetResize',
|
|
119
|
-
width: Math.ceil(rect.width),
|
|
120
|
-
height: Math.ceil(rect.height),
|
|
121
|
-
},
|
|
122
|
-
'*'
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
return () => {
|
|
128
|
-
observer.disconnect()
|
|
129
|
-
if (rafId) cancelAnimationFrame(rafId)
|
|
130
|
-
}
|
|
131
|
-
}, [])
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
**Integration point**: Call this hook in `widget.tsx` where the toggle state lives, or in `App.tsx`:
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// src/widget.tsx
|
|
139
|
-
export const Widget = (widgetConfig: WidgetConfigProps) => {
|
|
140
|
-
const [chatWindowStatus, toggleChatWindow] = useWidgetToggle(...)
|
|
141
|
-
useWidgetResize()
|
|
142
|
-
// ...
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Why ResizeObserver instead of state-based**:
|
|
147
|
-
- Catches ALL size changes (toggle, expand `DEFAULT`/`EXPANDED`/`FULLSCREEN`, window resize, content growth).
|
|
148
|
-
- No need to track which state variable caused the resize — the DOM is the source of truth.
|
|
149
|
-
- Reuses the same ResizeObserver pattern already used in `BotMain.tsx` (lines 70-81).
|
|
150
|
-
- Eliminates the `setTimeout(50ms)` race condition — the observer fires after layout.
|
|
151
|
-
- `requestAnimationFrame` throttling prevents flooding while staying responsive.
|
|
152
|
-
|
|
153
|
-
**Edge cases handled**:
|
|
154
|
-
- **Not in iframe**: Skip entirely — `window.parent === window`.
|
|
155
|
-
- **Zero dimensions**: Skip if measured width or height is 0 (DOM not ready).
|
|
156
|
-
- **Initial render**: Fires once on mount after the first rAF.
|
|
157
|
-
- **Flood protection**: One message per animation frame via `rafId` guard.
|
|
158
|
-
|
|
159
|
-
### Module 2: Backend Container Page — `server.html`
|
|
160
|
-
|
|
161
|
-
**File**: `server.html` (updated)
|
|
162
|
-
|
|
163
|
-
The backend serves a container page at `/embed/{widget_id}` that wraps the widget
|
|
164
|
-
in a resizable container using HubSpot's pattern. Customers embed this page as an
|
|
165
|
-
outer iframe on their SharePoint site.
|
|
166
|
-
|
|
167
|
-
**Updated `server.html`**:
|
|
168
|
-
|
|
169
|
-
```html
|
|
170
|
-
<!doctype html>
|
|
171
|
-
<html lang="en">
|
|
172
|
-
<head>
|
|
173
|
-
<meta charset="UTF-8" />
|
|
174
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
175
|
-
<title>Pager Widget</title>
|
|
176
|
-
<style>
|
|
177
|
-
body { margin: 0; overflow: hidden; }
|
|
178
|
-
</style>
|
|
179
|
-
</head>
|
|
180
|
-
<body>
|
|
181
|
-
<div id="pager-widget-container"
|
|
182
|
-
style="position:fixed;bottom:0;right:0;z-index:9999;min-height:60px;min-width:60px">
|
|
183
|
-
<iframe id="pager-widget-iframe"
|
|
184
|
-
src="https://dev.pagergpt.ai/wgt-hook/embed/ae320291-260f-48fc-a069-68ab73858664?v=1.0.10&SYS_FirstName=John&SYS_UserEmail=john@example.com"
|
|
185
|
-
style="position:absolute;width:100%!important;height:100%!important;border:none!important;bottom:0!important;right:0!important;background:transparent!important"
|
|
186
|
-
title="Pager Widget">
|
|
187
|
-
</iframe>
|
|
188
|
-
</div>
|
|
189
|
-
<script>
|
|
190
|
-
(function() {
|
|
191
|
-
var container = document.getElementById('pager-widget-container');
|
|
192
|
-
var iframe = document.getElementById('pager-widget-iframe');
|
|
193
|
-
|
|
194
|
-
// Listen for resize messages from the widget
|
|
195
|
-
window.addEventListener('message', function(event) {
|
|
196
|
-
if (event.data && event.data.type === 'widgetResize') {
|
|
197
|
-
container.style.width = event.data.width + 'px';
|
|
198
|
-
container.style.height = event.data.height + 'px';
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Send user details to the inner widget iframe
|
|
203
|
-
iframe.addEventListener('load', function() {
|
|
204
|
-
iframe.contentWindow.postMessage({
|
|
205
|
-
type: 'userDetails',
|
|
206
|
-
data: {
|
|
207
|
-
SYS_FirstName: "{{firstName}}",
|
|
208
|
-
SYS_LastName: "{{lastName}}",
|
|
209
|
-
SYS_UserEmail: "{{email}}",
|
|
210
|
-
SYS_Location: "{{location}}",
|
|
211
|
-
SYS_Timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
212
|
-
}
|
|
213
|
-
}, 'https://dev.pagergpt.ai');
|
|
214
|
-
});
|
|
215
|
-
})();
|
|
216
|
-
</script>
|
|
217
|
-
</body>
|
|
218
|
-
</html>
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**Container CSS breakdown**:
|
|
222
|
-
|
|
223
|
-
| Property | Value | Purpose |
|
|
224
|
-
|---|---|---|
|
|
225
|
-
| `position: fixed` | bottom; right | Anchors widget to viewport corner, scrolls with page |
|
|
226
|
-
| `z-index: 9999` | high value | Stays above page content |
|
|
227
|
-
| `min-height: 60px` | launcher button height | Prevents collapse to zero before first message |
|
|
228
|
-
| `min-width: 60px` | launcher button width | Prevents collapse to zero before first message |
|
|
229
|
-
| `width` / `height` | set dynamically | Updated by message listener |
|
|
230
|
-
|
|
231
|
-
**Inner iframe CSS breakdown**:
|
|
232
|
-
|
|
233
|
-
| Property | Value | Purpose |
|
|
234
|
-
|---|---|---|
|
|
235
|
-
| `position: absolute` | — | Fills the container, not the viewport |
|
|
236
|
-
| `width: 100% !important` | — | Matches container width |
|
|
237
|
-
| `height: 100% !important` | — | Matches container height |
|
|
238
|
-
| `border: none !important` | — | No visible border |
|
|
239
|
-
| `background: transparent !important` | — | No white flash behind the widget |
|
|
240
|
-
|
|
241
|
-
**Security**: The `postMessage` listener does not check `event.origin` since different customers have different SharePoint domains. The widget side uses `targetOrigin: '*'`. This can be hardened later with a known-allowlist of customer origins.
|
|
242
|
-
|
|
243
|
-
### Module 3: Backend iframe HTML Template
|
|
244
|
-
|
|
245
|
-
**File**: `src/public/public.router.ts` (existing — no changes to the router)
|
|
246
|
-
|
|
247
|
-
The backend route `GET /embed/:widget_id` continues to serve `server.html`.
|
|
248
|
-
The template variables (`{{firstName}}`, `{{email}}`, etc.) are filled in by
|
|
249
|
-
the backend. No router changes are needed — only the template file itself
|
|
250
|
-
is updated (Module 2).
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
## Testing Decisions
|
|
255
|
-
|
|
256
|
-
### What makes a good test
|
|
257
|
-
|
|
258
|
-
- Test the **contract**: when the widget toggles state, a `postMessage` with the correct shape is dispatched.
|
|
259
|
-
- Test **edge cases**: not in iframe (skip), zero dimensions (skip), DOM not ready (skip).
|
|
260
|
-
- Do NOT test the parent page's resize behavior — that requires a browser/DOM environment and is covered by manual QA.
|
|
261
|
-
|
|
262
|
-
### Tests for Module 1 (useWidgetResize hook)
|
|
263
|
-
|
|
264
|
-
**File**: `src/__tests__/useWidgetResize.test.ts`
|
|
265
|
-
|
|
266
|
-
| Test | Input | Expected |
|
|
267
|
-
|---|---|---|
|
|
268
|
-
| ResizeObserver fires on size change | Mock ResizeObserver with 400×600 rect | `postMessage` called with `{ type: 'widgetResize', width: 400, height: 600 }` |
|
|
269
|
-
| Skip if not in iframe | `window.parent === window` | `postMessage` NOT called |
|
|
270
|
-
| Skip if dimensions are zero | Mock ResizeObserver with 0×0 rect | `postMessage` NOT called |
|
|
271
|
-
| Initial mount fires one message | Simulate mount + rAF | `postMessage` called with actual dimensions |
|
|
272
|
-
| Cleanup on unmount | Disconnect observer + cancel rAF | Observer.disconnect() called |
|
|
273
|
-
|
|
274
|
-
### Prior art
|
|
275
|
-
|
|
276
|
-
No existing tests in `poc-pager-widget` — this is the first. `vitest` must be installed as a devDependency along with `jsdom` environment.
|
|
277
|
-
|
|
278
|
-
```bash
|
|
279
|
-
npm install -D vitest jsdom
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
## Integration Points
|
|
285
|
-
|
|
286
|
-
### Where to connect
|
|
287
|
-
|
|
288
|
-
```
|
|
289
|
-
server.html (served at /embed/{widget_id})
|
|
290
|
-
│
|
|
291
|
-
├── Container div (fixed, bottom-right, min 60×60)
|
|
292
|
-
│ └── Inner iframe → Widget React App
|
|
293
|
-
│ │
|
|
294
|
-
│ ├── widget.tsx
|
|
295
|
-
│ │ ├── useWidgetToggle() ← existing
|
|
296
|
-
│ │ ├── useWidgetResize() ← NEW (ResizeObserver)
|
|
297
|
-
│ │ └── <WidgetToggleButton ... />
|
|
298
|
-
│ │
|
|
299
|
-
│ └── ResizeObserver fires → postMessage({ type: 'widgetResize', width, height })
|
|
300
|
-
│
|
|
301
|
-
└── Message listener receives postMessage
|
|
302
|
-
└── container.style.width = ...px
|
|
303
|
-
└── container.style.height = ...px
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Where is the toggle state?
|
|
307
|
-
|
|
308
|
-
The widget already has a way to toggle open/collapsed. Find the existing open/close state — likely one of:
|
|
309
|
-
- `widgetStore.ts` — the main xstate store
|
|
310
|
-
- `widgetControlstore.ts` — widget control state
|
|
311
|
-
- `WidgetToggleButton.tsx` — the toggle button component
|
|
312
|
-
|
|
313
|
-
The hook needs to read this state. The exact store/state key needs to be identified during implementation.
|
|
314
|
-
|
|
315
|
-
---
|
|
316
|
-
|
|
317
|
-
## Out of Scope
|
|
318
|
-
|
|
319
|
-
- **Animation or transitions**: Container resize is instant. CSS `transition` on the container can be added later.
|
|
320
|
-
- **Responsive dimensions**: The widget does not need to send resize events on window resize — ResizeObserver handles this automatically.
|
|
321
|
-
- **Multiple widget instances**: Only one widget per page is supported.
|
|
322
|
-
- **Mobile considerations**: The same pattern works on mobile. The dimensions sent will naturally be smaller due to viewport size. No special mobile handling needed.
|
|
323
|
-
- **origin validation**: The parent page listens unconditionally. If needed later, the widget can harden `targetOrigin` or validate `event.origin`.
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
## Further Notes
|
|
328
|
-
|
|
329
|
-
- HubSpot's own widget uses exactly the container-resize pattern. Their container starts at minimum size and gets resized dynamically. This is a proven pattern used at scale.
|
|
330
|
-
- The initial `min-height: 60px; min-width: 60px` matches the approximate launcher button size. When the widget first loads and sends its first `widgetResize` message, the container is resized to the actual rendered dimensions.
|
|
331
|
-
- If the widget fails to send the initial resize message (e.g., JS error), the container stays at 60×60px — users will see a tiny square but the page remains fully functional. This is a safe failure mode.
|
|
332
|
-
- The ResizeObserver fires for ANY size change: toggle open/close, expand (DEFAULT/EXPANDED/FULLSCREEN), window resize, or content growth. This is more robust than state-based triggers.
|
|
333
|
-
- The widget URL (`https://dev.pagergpt.ai/wgt-hook/embed/{widget_id}?v={version}`) that the inner iframe loads is unaffected by this change — only `server.html` (the outer container page) is updated.
|
package/test-iframe-resize.html
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Iframe Resize Test</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { margin: 0; min-height: 200vh; background: #f5f5f5; font-family: sans-serif; }
|
|
9
|
-
.page-content { padding: 40px; max-width: 600px; }
|
|
10
|
-
h1 { color: #333; }
|
|
11
|
-
p { color: #666; line-height: 1.6; margin-bottom: 20px; }
|
|
12
|
-
.debug-panel {
|
|
13
|
-
position: fixed; top: 10px; left: 10px; z-index: 99999;
|
|
14
|
-
background: rgba(0,0,0,0.8); color: #0f0; padding: 10px 14px;
|
|
15
|
-
border-radius: 8px; font-size: 13px; font-family: monospace;
|
|
16
|
-
max-width: 300px;
|
|
17
|
-
}
|
|
18
|
-
.debug-panel div { margin: 2px 0; }
|
|
19
|
-
</style>
|
|
20
|
-
</head>
|
|
21
|
-
<body>
|
|
22
|
-
<div class="page-content">
|
|
23
|
-
<h1>Pager Widget — Iframe Resize Test</h1>
|
|
24
|
-
<p>This page simulates the container pattern from <code>server.html</code>.</p>
|
|
25
|
-
<p>The widget loads inside an iframe that is contained within a fixed-position
|
|
26
|
-
container div. The container starts at 60×60px and gets resized dynamically
|
|
27
|
-
when the widget sends <code>widgetResize</code> postMessages.</p>
|
|
28
|
-
<p><strong>Test checklist:</strong></p>
|
|
29
|
-
<ul>
|
|
30
|
-
<li>Page should be scrollable at all times (not blocked by iframe)</li>
|
|
31
|
-
<li>Widget launcher should be clickable</li>
|
|
32
|
-
<li>Opening the widget should resize the container (watch debug panel)</li>
|
|
33
|
-
<li>Clicking the X should collapse the widget and shrink the container</li>
|
|
34
|
-
<li>Clicking expand buttons (EXPANDED / FULLSCREEN) should resize container</li>
|
|
35
|
-
<li>Page content behind the widget should remain clickable</li>
|
|
36
|
-
</ul>
|
|
37
|
-
<p style="margin-top: 60vh;">↓ Scroll down (should work even with widget open)</p>
|
|
38
|
-
<p style="margin-top: 40vh;">Bottom of page. Scrolling worked!</p>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<!-- Container div with iframe (mimics server.html pattern) -->
|
|
42
|
-
<div id="pager-widget-container"
|
|
43
|
-
style="position:fixed;bottom:0;right:0;z-index:9999;min-height:60px;min-width:60px">
|
|
44
|
-
<iframe id="pager-widget-iframe"
|
|
45
|
-
src="http://localhost:8000/embed/ae320291-260f-48fc-a069-68ab73858664?v=1.0.11-alpha.7&SYS_FirstName=John&SYS_UserEmail=john@example.com"
|
|
46
|
-
style="position:absolute;width:100%;height:100%;border:none;background:transparent"
|
|
47
|
-
title="Pager Widget">
|
|
48
|
-
</iframe>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<script>
|
|
52
|
-
(function() {
|
|
53
|
-
var container = document.getElementById('pager-widget-container');
|
|
54
|
-
|
|
55
|
-
// Debug panel
|
|
56
|
-
var debug = document.createElement('div');
|
|
57
|
-
debug.className = 'debug-panel';
|
|
58
|
-
debug.innerHTML = '<div><strong>Resize Debug</strong></div><div id="debug-size">waiting...</div>';
|
|
59
|
-
document.body.appendChild(debug);
|
|
60
|
-
var debugSize = document.getElementById('debug-size');
|
|
61
|
-
|
|
62
|
-
window.addEventListener('message', function(event) {
|
|
63
|
-
console.log(event.data, "from inside iframe");
|
|
64
|
-
if (event.data && event.data.type === 'widgetResize') {
|
|
65
|
-
container.style.width = (Number(event.data.width) + 100) + 'px';
|
|
66
|
-
container.style.height = (Number(event.data.height) + 200) + 'px';
|
|
67
|
-
debugSize.textContent = event.data.width + ' x ' + event.data.height;
|
|
68
|
-
console.log('[widgetResize]', event.data.width, 'x', event.data.height);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
})();
|
|
72
|
-
</script>
|
|
73
|
-
</body>
|
|
74
|
-
</html>
|